You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by db...@apache.org on 2021/03/26 07:55:24 UTC

[netbeans] branch master updated: Micronaut support (#2812)

This is an automated email from the ASF dual-hosted git repository.

dbalek pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new 3bf5558  Micronaut support (#2812)
3bf5558 is described below

commit 3bf55585368d30191e080649fbfa846183d5c005
Author: Dusan Balek <du...@oracle.com>
AuthorDate: Fri Mar 26 08:55:07 2021 +0100

    Micronaut support (#2812)
    
    * Micronaut support module added.
    * Yaml parser enhanced with error recovery.
    * JCodings library wapper module created to prevent overlaps.
    * LSP: Navigation between Micronaut config yaml files and Java sources.
    * Code completion in Micronaut config yaml files available via LSP.
---
 enterprise/micronaut/build.xml                     |  25 +
 .../android-json-0.0.20131108.vaadin1-license.txt  | 209 +++++
 .../micronaut/external/binaries-list               |   6 +-
 ...g-boot-configuration-metadata-2.4.4-license.txt | 210 +++++
 enterprise/micronaut/manifest.mf                   |   7 +
 .../micronaut}/nbproject/project.properties        |  15 +-
 .../micronaut}/nbproject/project.xml               | 202 +++--
 .../netbeans/modules/micronaut/Bundle.properties   |   5 +-
 .../micronaut/MicronautConfigProperties.java       |  90 +++
 .../micronaut/MicronautConfigUtilities.java        | 220 ++++++
 .../MicronautConfigCompletionCollector.java        | 101 +++
 .../completion/MicronautConfigCompletionItem.java  | 302 ++++++++
 .../MicronautConfigCompletionProvider.java         | 117 +++
 .../completion/MicronautConfigCompletionTask.java  | 207 +++++
 .../completion/MicronautConfigDocumentation.java   | 104 +++
 .../MicronautJavaConfigPropertiesCompletion.java   | 140 ++++
 .../MicronautConfigHyperlinkProvider.java          | 152 ++++
 .../hyperlink/MicronautJavaHyperlinkProvider.java  | 205 +++++
 .../micronaut/newproject/BasePropertiesVisual.form | 348 +++++++++
 .../micronaut/newproject/BasePropertiesVisual.java | 424 ++++++++++
 .../newproject/BasePropertiesWizardPanel.java      | 108 +++
 .../modules/micronaut/newproject/Bundle.properties |  27 +-
 .../micronaut/newproject/FeatureTogglePanel.form   |  78 ++
 .../micronaut/newproject/FeatureTogglePanel.java   |  89 +++
 .../micronaut/newproject/FeaturesVisual.form       |  64 ++
 .../micronaut/newproject/FeaturesVisual.java       | 190 +++++
 .../micronaut/newproject/FeaturesWizardPanel.java  | 109 +++
 .../MicronautGradleProjectDescription.html         |  29 +
 .../newproject/MicronautLaunchService.java         | 174 +++++
 .../MicronautMavenProjectDescription.html          |  29 +
 .../newproject/MicronautProjectWizardIterator.java | 224 ++++++
 .../newproject/NameAndLocationVisual.form          | 141 ++++
 .../newproject/NameAndLocationVisual.java          | 273 +++++++
 .../newproject/NameAndLocationWizardPanel.java     | 108 +++
 .../refactor/MicronautRefactoringFactory.java      | 243 ++++++
 .../netbeans/modules/micronaut/resources/layer.xml |  33 +
 .../modules/micronaut/resources/micronaut.png      | Bin 0 -> 503 bytes
 ide/api.lsp/build.xml                              |  25 +
 ide/api.lsp/manifest.mf                            |   6 +
 .../nbproject/project.properties}                  |   5 +-
 ide/api.lsp/nbproject/project.xml                  | 105 +++
 .../src/org/netbeans/api/lsp/Bundle.properties}    |   7 +-
 .../src/org/netbeans/api/lsp/Completion.java       | 392 ++++++++++
 .../org/netbeans/api/lsp/HyperlinkLocation.java    | 160 ++++
 ide/api.lsp/src/org/netbeans/api/lsp/TextEdit.java |  70 ++
 .../netbeans/modules/lsp/CompletionAccessor.java   |  60 ++
 .../modules/lsp/HyperlinkLocationAccessor.java     |  53 ++
 .../org/netbeans/spi/lsp/CompletionCollector.java  | 358 +++++++++
 .../spi/lsp/HyperlinkLocationProvider.java         |  72 ++
 .../src/org/netbeans/api/lsp/CompletionTest.java   | 131 ++++
 .../csl/editor/completion/GsfCompletionDoc.java    |   7 +-
 .../editor/completion/GsfCompletionProvider.java   |   2 +-
 .../modules/languages/yaml/YamlCompletion.java     |  18 +-
 .../modules/languages/yaml/YamlParser.java         | 125 +--
 ide/libs.bytelist/external/binaries-list           |   3 +-
 ide/libs.bytelist/nbproject/project.properties     |   3 +-
 ide/libs.bytelist/nbproject/project.xml            |  14 +-
 ide/libs.jcodings/build.xml                        |  24 +
 .../external/binaries-list                         |   1 -
 .../external/jcodings-1.0.18-license.txt           |   0
 ide/libs.jcodings/manifest.mf                      |   4 +
 .../nbproject/project.properties                   |   2 -
 .../nbproject/project.xml                          |  20 +-
 .../org/netbeans/libs/jcodings/Bundle.properties}  |   9 +-
 ide/textmate.lexer/external/binaries-list          |   1 -
 .../external/jcodings-1.0.18-license.txt           |  23 -
 ide/textmate.lexer/nbproject/project.properties    |   3 +-
 ide/textmate.lexer/nbproject/project.xml           |  11 +-
 java/java.editor/nbproject/project.xml             |  11 +-
 .../netbeans/modules/editor/java/GoToSupport.java  |  55 +-
 .../editor/java/JavaCompletionCollector.java       | 548 +++++++++++++
 .../editor/hyperlink/JavaHyperlinkProvider.java    |  20 +-
 .../nbcode/nbproject/platform.properties           | 113 ++-
 java/java.lsp.server/nbproject/project.xml         |  23 +-
 java/java.lsp.server/script/etc/nbcode.clusters    |   1 +
 .../server/protocol/TextDocumentServiceImpl.java   | 855 ++++++---------------
 java/java.lsp.server/vscode/src/extension.ts       |   2 +-
 java/java.sourceui/apichanges.xml                  |  12 +
 java/java.sourceui/nbproject/project.properties    |   2 +-
 java/java.sourceui/nbproject/project.xml           |   9 +
 .../netbeans/api/java/source/ui/ElementOpen.java   | 119 +++
 .../java/plugins/JavaWhereUsedQueryPlugin.java     |   4 +-
 .../org/netbeans/nbbuild/extlibs/ignored-overlaps  |   3 -
 nbbuild/cluster.properties                         |   3 +
 84 files changed, 7572 insertions(+), 930 deletions(-)

diff --git a/enterprise/micronaut/build.xml b/enterprise/micronaut/build.xml
new file mode 100644
index 0000000..90188c2
--- /dev/null
+++ b/enterprise/micronaut/build.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<project basedir="." default="netbeans" name="enterprise/micronaut">
+    <description>Builds, tests, and runs the project org.netbeans.modules.micronaut</description>
+    <import file="../../nbbuild/templates/projectized.xml"/>
+</project>
diff --git a/enterprise/micronaut/external/android-json-0.0.20131108.vaadin1-license.txt b/enterprise/micronaut/external/android-json-0.0.20131108.vaadin1-license.txt
new file mode 100644
index 0000000..e24e220
--- /dev/null
+++ b/enterprise/micronaut/external/android-json-0.0.20131108.vaadin1-license.txt
@@ -0,0 +1,209 @@
+Name: JSON library from Android SDK
+Description: JSON (JavaScript Object Notation) is a lightweight data-interchange format. This is the org.json compatible Android implementation extracted from the Android SDK
+Version: 0.0.20131108.vaadin1
+License: Apache-2.0
+Origin: Google
+Source: http://developer.android.com/sdk/
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/ide/libs.bytelist/nbproject/project.properties b/enterprise/micronaut/external/binaries-list
similarity index 79%
copy from ide/libs.bytelist/nbproject/project.properties
copy to enterprise/micronaut/external/binaries-list
index 20a62cb..52d00e4 100644
--- a/ide/libs.bytelist/nbproject/project.properties
+++ b/enterprise/micronaut/external/binaries-list
@@ -15,7 +15,5 @@
 # specific language governing permissions and limitations
 # under the License.
 
-is.autoload=true
-release.external/bytelist-1.0.15.jar=modules/ext/bytelist-1.0.15.jar
-release.external/jcodings-1.0.18.jar=modules/ext/jcodings-1.0.18.jar
-spec.version.base=0.41.0
+5F7BD843949ED9DEF4A13632D11C6ABE4EDBBE09 org.springframework.boot:spring-boot-configuration-metadata:2.4.4
+FA26D351FE62A6A17F5CDA1287C1C6110DEC413F com.vaadin.external.google:android-json:0.0.20131108.vaadin1
\ No newline at end of file
diff --git a/enterprise/micronaut/external/spring-boot-configuration-metadata-2.4.4-license.txt b/enterprise/micronaut/external/spring-boot-configuration-metadata-2.4.4-license.txt
new file mode 100644
index 0000000..e3c448f
--- /dev/null
+++ b/enterprise/micronaut/external/spring-boot-configuration-metadata-2.4.4-license.txt
@@ -0,0 +1,210 @@
+Name: Spring Boot Configuration Metadata
+Description: Spring Boot Configuration Metadata library
+Version: 2.4.4
+License: Apache-2.0
+Origin: Pivotal Software, Inc.
+URL: https://spring.io/projects/spring-boot
+Source: https://github.com/spring-projects/spring-boot
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/enterprise/micronaut/manifest.mf b/enterprise/micronaut/manifest.mf
new file mode 100644
index 0000000..cec26e3
--- /dev/null
+++ b/enterprise/micronaut/manifest.mf
@@ -0,0 +1,7 @@
+Manifest-Version: 1.0
+AutoUpdate-Show-In-Client: true
+OpenIDE-Module: org.netbeans.modules.micronaut
+OpenIDE-Module-Layer: org/netbeans/modules/micronaut/resources/layer.xml
+OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/micronaut/Bundle.properties
+OpenIDE-Module-Implementation-Version: 1
+
diff --git a/java/java.sourceui/nbproject/project.properties b/enterprise/micronaut/nbproject/project.properties
similarity index 77%
copy from java/java.sourceui/nbproject/project.properties
copy to enterprise/micronaut/nbproject/project.properties
index 01b9ec4..037c5e3 100644
--- a/java/java.sourceui/nbproject/project.properties
+++ b/enterprise/micronaut/nbproject/project.properties
@@ -14,14 +14,9 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-javadoc.apichanges=${basedir}/apichanges.xml
-javac.compilerargs=-Xlint -Xlint:-serial
-javac.source=1.8
-javadoc.arch=${basedir}/arch.xml
-spec.version.base=1.57.0
-
-test.config.stableBTD.includes=**/*Test.class
-test.config.stableBTD.excludes=\
-    **/ElementHeadersTest.class
 
-requires.nb.javac=true
+javac.source=1.8
+javac.compilerargs=-Xlint -Xlint:-serial
+release.external/spring-boot-configuration-metadata-2.4.4.jar=modules/ext/spring-boot-configuration-metadata-2.4.4.jar
+release.external/android-json-0.0.20131108.vaadin1.jar=modules/ext/android-json-0.0.20131108.vaadin1.jar
+spec.version.base=1.0
diff --git a/java/java.sourceui/nbproject/project.xml b/enterprise/micronaut/nbproject/project.xml
similarity index 66%
copy from java/java.sourceui/nbproject/project.xml
copy to enterprise/micronaut/nbproject/project.xml
index 33f9b27..e15395e 100644
--- a/java/java.sourceui/nbproject/project.xml
+++ b/enterprise/micronaut/nbproject/project.xml
@@ -23,28 +23,27 @@
     <type>org.netbeans.modules.apisupport.project</type>
     <configuration>
         <data xmlns="http://www.netbeans.org/ns/nb-module-project/3">
-            <code-name-base>org.netbeans.modules.java.sourceui</code-name-base>
+            <code-name-base>org.netbeans.modules.micronaut</code-name-base>
             <module-dependencies>
                 <dependency>
-                    <code-name-base>org.netbeans.api.annotations.common</code-name-base>
+                    <code-name-base>com.google.gson</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
-                        <release-version>1</release-version>
-                        <specification-version>1.10</specification-version>
+                        <specification-version>2.7</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
-                    <code-name-base>org.netbeans.api.java</code-name-base>
+                    <code-name-base>org.netbeans.api.java.classpath</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
                         <release-version>1</release-version>
-                        <specification-version>1.35</specification-version>
+                        <specification-version>1.65</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
-                    <code-name-base>org.netbeans.api.java.classpath</code-name-base>
+                    <code-name-base>org.netbeans.api.lsp</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
@@ -58,15 +57,15 @@
                     <compile-dependency/>
                     <run-dependency>
                         <release-version>1</release-version>
-                        <specification-version>1.40</specification-version>
+                        <specification-version>1.59</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
-                    <code-name-base>org.netbeans.api.progress.nb</code-name-base>
+                    <code-name-base>org.netbeans.api.templates</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
-                        <specification-version>1.40</specification-version>
+                        <specification-version>1.19</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
@@ -74,77 +73,96 @@
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
-                        <specification-version>8.19</specification-version>
+                        <specification-version>8.33</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
-                    <code-name-base>org.netbeans.libs.javacimpl</code-name-base>
+                    <code-name-base>org.netbeans.modules.csl.api</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
-                        <release-version>1</release-version>
+                        <release-version>2</release-version>
                         <implementation-version/>
                     </run-dependency>
                 </dependency>
                 <dependency>
-                    <code-name-base>org.netbeans.libs.lucene</code-name-base>
+                    <code-name-base>org.netbeans.modules.csl.types</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
-                        <release-version>3</release-version>
-                        <specification-version>3.0</specification-version>
+                        <release-version>1</release-version>
+                        <specification-version>1.11</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
-                    <code-name-base>org.netbeans.modules.editor.fold</code-name-base>
+                    <code-name-base>org.netbeans.modules.editor.codetemplates</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
                         <release-version>1</release-version>
-                        <specification-version>1.39</specification-version>
+                        <specification-version>1.54</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
-                    <code-name-base>org.netbeans.modules.editor.lib2</code-name-base>
+                    <code-name-base>org.netbeans.modules.editor.completion</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
                         <release-version>1</release-version>
-                        <specification-version>2.0</specification-version>
+                        <specification-version>1.56</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
-                    <code-name-base>org.netbeans.modules.java.lexer</code-name-base>
+                    <code-name-base>org.netbeans.modules.editor.document</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
-                        <release-version>1</release-version>
-                        <specification-version>1.2</specification-version>
+                        <specification-version>1.20</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.netbeans.modules.editor.indent</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>2</release-version>
+                        <specification-version>1.54</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.netbeans.modules.editor.lib</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>3</release-version>
+                        <specification-version>4.18</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
-                    <code-name-base>org.netbeans.modules.java.platform</code-name-base>
+                    <code-name-base>org.netbeans.modules.editor.mimelookup</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
                         <release-version>1</release-version>
-                        <specification-version>1.9</specification-version>
+                        <specification-version>1.51</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
-                    <code-name-base>org.netbeans.modules.java.preprocessorbridge</code-name-base>
+                    <code-name-base>org.netbeans.modules.editor.util</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
-                        <specification-version>1.3</specification-version>
+                        <release-version>1</release-version>
+                        <specification-version>1.76</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
-                    <code-name-base>org.netbeans.modules.java.source</code-name-base>
+                    <code-name-base>org.netbeans.modules.java.project</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
-                        <implementation-version/>
+                        <release-version>1</release-version>
+                        <specification-version>1.83</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
@@ -152,16 +170,16 @@
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
-                        <implementation-version/>
+                        <specification-version>2.49</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
-                    <code-name-base>org.netbeans.modules.jumpto</code-name-base>
+                    <code-name-base>org.netbeans.modules.java.sourceui</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
                         <release-version>1</release-version>
-                        <specification-version>1.50</specification-version>
+                        <specification-version>1.58</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
@@ -170,7 +188,7 @@
                     <compile-dependency/>
                     <run-dependency>
                         <release-version>2</release-version>
-                        <specification-version>1.20</specification-version>
+                        <specification-version>1.74</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
@@ -179,42 +197,41 @@
                     <compile-dependency/>
                     <run-dependency>
                         <release-version>1</release-version>
-                        <specification-version>9.0</specification-version>
+                        <specification-version>9.18</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
-                    <code-name-base>org.netbeans.modules.parsing.indexing</code-name-base>
+                    <code-name-base>org.netbeans.modules.projectapi</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
-                        <specification-version>9.0</specification-version>
+                        <release-version>1</release-version>
+                        <specification-version>1.79</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
-                    <code-name-base>org.netbeans.modules.parsing.lucene</code-name-base>
+                    <code-name-base>org.netbeans.modules.projectuiapi</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
-                        <release-version>2</release-version>
-                        <specification-version>2.9</specification-version>
+                        <release-version>1</release-version>
+                        <specification-version>1.99</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
-                    <code-name-base>org.netbeans.modules.projectapi</code-name-base>
+                    <code-name-base>org.netbeans.modules.refactoring.api</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
-                        <release-version>1</release-version>
-                        <specification-version>1.13</specification-version>
+                        <specification-version>1.58</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
-                    <code-name-base>org.netbeans.modules.projectuiapi.base</code-name-base>
+                    <code-name-base>org.netbeans.swing.plaf</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
-                        <release-version>1</release-version>
-                        <specification-version>1.78</specification-version>
+                        <specification-version>1.53</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
@@ -222,7 +239,7 @@
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
-                        <specification-version>6.11</specification-version>
+                        <specification-version>7.79</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
@@ -230,7 +247,7 @@
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
-                        <specification-version>7.5</specification-version>
+                        <specification-version>7.53</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
@@ -238,7 +255,7 @@
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
-                        <specification-version>9.0</specification-version>
+                        <specification-version>9.21</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
@@ -246,112 +263,67 @@
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
-                        <specification-version>7.61</specification-version>
+                        <specification-version>7.80</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
-                    <code-name-base>org.openide.modules</code-name-base>
+                    <code-name-base>org.openide.nodes</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
-                        <specification-version>7.28</specification-version>
+                        <specification-version>7.56</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
-                    <code-name-base>org.openide.nodes</code-name-base>
+                    <code-name-base>org.openide.text</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
-                        <specification-version>7.2</specification-version>
+                        <specification-version>6.78</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
-                    <code-name-base>org.openide.text</code-name-base>
+                    <code-name-base>org.openide.util</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
-                        <specification-version>6.16</specification-version>
+                        <specification-version>9.18</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
-                    <code-name-base>org.openide.util</code-name-base>
+                    <code-name-base>org.openide.util.lookup</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
-                        <specification-version>9.3</specification-version>
+                        <specification-version>8.45</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
-                    <code-name-base>org.openide.util.lookup</code-name-base>
+                    <code-name-base>org.openide.util.ui</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
-                        <specification-version>8.0</specification-version>
+                        <specification-version>9.19</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
-                    <code-name-base>org.openide.util.ui</code-name-base>
+                    <code-name-base>org.openide.windows</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
-                        <specification-version>9.3</specification-version>
+                        <specification-version>6.88</specification-version>
                     </run-dependency>
                 </dependency>
             </module-dependencies>
-            <test-dependencies>
-                <test-type>
-                    <name>unit</name>
-                    <test-dependency>
-                        <code-name-base>org.netbeans.core</code-name-base>
-                        <recursive/>
-                    </test-dependency>
-                    <test-dependency>
-                        <code-name-base>org.netbeans.insane</code-name-base>
-                        <compile-dependency/>
-                    </test-dependency>
-                    <test-dependency>
-                        <code-name-base>org.netbeans.libs.junit4</code-name-base>
-                        <compile-dependency/>
-                    </test-dependency>
-                    <test-dependency>
-                        <code-name-base>org.netbeans.modules.java.lexer</code-name-base>
-                        <compile-dependency/>
-                    </test-dependency>
-                    <test-dependency>
-                        <code-name-base>org.netbeans.modules.java.platform</code-name-base>
-                        <compile-dependency/>
-                    </test-dependency>
-                    <test-dependency>
-                        <code-name-base>org.netbeans.modules.java.source.base</code-name-base>
-                        <recursive/>
-                        <compile-dependency/>
-                        <test/>
-                    </test-dependency>
-                    <test-dependency>
-                        <code-name-base>org.netbeans.modules.lexer</code-name-base>
-                        <compile-dependency/>
-                    </test-dependency>
-                    <test-dependency>
-                        <code-name-base>org.netbeans.modules.nbjunit</code-name-base>
-                        <compile-dependency/>
-                    </test-dependency>
-                    <test-dependency>
-                        <code-name-base>org.netbeans.modules.parsing.api</code-name-base>
-                        <compile-dependency/>
-                        <test/>
-                    </test-dependency>
-                    <test-dependency>
-                        <code-name-base>org.netbeans.modules.parsing.nb</code-name-base>
-                        <compile-dependency/>
-                    </test-dependency>
-                    <test-dependency>
-                        <code-name-base>org.netbeans.modules.projectapi.nb</code-name-base>
-                    </test-dependency>
-                </test-type>
-            </test-dependencies>
-            <public-packages>
-                <package>org.netbeans.api.java.source.ui</package>
-            </public-packages>
+            <public-packages/>
+            <class-path-extension>
+                <runtime-relative-path>ext/spring-boot-configuration-metadata-2.4.4.jar</runtime-relative-path>
+                <binary-origin>external/spring-boot-configuration-metadata-2.4.4.jar</binary-origin>
+            </class-path-extension>
+            <class-path-extension>
+                <runtime-relative-path>ext/android-json-0.0.20131108.vaadin1.jar</runtime-relative-path>
+                <binary-origin>external/android-json-0.0.20131108.vaadin1.jar</binary-origin>
+            </class-path-extension>
         </data>
     </configuration>
 </project>
diff --git a/ide/libs.bytelist/external/binaries-list b/enterprise/micronaut/src/org/netbeans/modules/micronaut/Bundle.properties
similarity index 83%
copy from ide/libs.bytelist/external/binaries-list
copy to enterprise/micronaut/src/org/netbeans/modules/micronaut/Bundle.properties
index 0e0b70c1..b7f6a8b 100644
--- a/ide/libs.bytelist/external/binaries-list
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/Bundle.properties
@@ -14,5 +14,6 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-80294E59315B314D57782DC37F983AE5B29C2E4C org.jruby.extras:bytelist:1.0.15
-E2C76A19F00128BB1806207E2989139BFB45F49D org.jruby.jcodings:jcodings:1.0.18
+
+OpenIDE-Module-Name=Micronaut Support
+OpenIDE-Module-Display-Category=Java Web and EE
\ No newline at end of file
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/MicronautConfigProperties.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/MicronautConfigProperties.java
new file mode 100644
index 0000000..163171c
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/MicronautConfigProperties.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.micronaut;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import org.netbeans.api.java.classpath.ClassPath;
+import org.netbeans.api.java.project.JavaProjectConstants;
+import org.netbeans.api.project.Project;
+import org.netbeans.api.project.ProjectUtils;
+import org.netbeans.api.project.SourceGroup;
+import org.openide.filesystems.FileObject;
+import org.openide.util.Exceptions;
+import org.springframework.boot.configurationmetadata.ConfigurationMetadataGroup;
+import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;
+import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepository;
+import org.springframework.boot.configurationmetadata.ConfigurationMetadataRepositoryJsonBuilder;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+public final class MicronautConfigProperties {
+
+    private static final String CONFIG_METADATA_JSON = "META-INF/spring-configuration-metadata.json";
+
+    private MicronautConfigProperties() {
+    }
+
+    public static boolean hasConfigMetadata(Project project) {
+        ClassPath cp = getExecuteClasspath(project);
+        return cp != null && !cp.findAllResources(CONFIG_METADATA_JSON).isEmpty();
+    }
+
+    public static Map<String, ConfigurationMetadataProperty> getProperties(Project project) {
+        Map<String, ConfigurationMetadataProperty> props = new LinkedHashMap<>();
+        ClassPath cp = getExecuteClasspath(project);
+        if (cp != null) {
+            for (FileObject fo : cp.findAllResources(CONFIG_METADATA_JSON)) {
+                try {
+                    ConfigurationMetadataRepository repository = ConfigurationMetadataRepositoryJsonBuilder.create().withJsonResource(fo.getInputStream()).build();
+                    props.putAll(repository.getAllProperties());
+                } catch (Exception ex) {
+                    Exceptions.printStackTrace(ex);
+                }
+            }
+        }
+        return props;
+    }
+
+    public static Map<String, ConfigurationMetadataGroup> getGroups(Project project) {
+        Map<String, ConfigurationMetadataGroup> groups = new LinkedHashMap<>();
+        ClassPath cp = getExecuteClasspath(project);
+        if (cp != null) {
+            for (FileObject fo : cp.findAllResources(CONFIG_METADATA_JSON)) {
+                try {
+                    ConfigurationMetadataRepository repository = ConfigurationMetadataRepositoryJsonBuilder.create().withJsonResource(fo.getInputStream()).build();
+                    groups.putAll(repository.getAllGroups());
+                } catch (Exception ex) {
+                    Exceptions.printStackTrace(ex);
+                }
+            }
+        }
+        return groups;
+    }
+
+    private static ClassPath getExecuteClasspath(Project project) {
+        SourceGroup[] srcGroups = ProjectUtils.getSources(project).getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA);
+        if (srcGroups.length > 0) {
+            return ClassPath.getClassPath(srcGroups[0].getRootFolder(), ClassPath.EXECUTE);
+        }
+        return null;
+    }
+}
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/MicronautConfigUtilities.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/MicronautConfigUtilities.java
new file mode 100644
index 0000000..b95425b
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/MicronautConfigUtilities.java
@@ -0,0 +1,220 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.micronaut;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+import java.util.regex.Pattern;
+import javax.swing.text.Document;
+import org.netbeans.api.editor.document.EditorDocumentUtils;
+import org.netbeans.api.editor.document.LineDocument;
+import org.netbeans.api.editor.document.LineDocumentUtils;
+import org.netbeans.api.project.FileOwnerQuery;
+import org.netbeans.api.project.Project;
+import org.netbeans.modules.csl.api.StructureItem;
+import org.netbeans.modules.csl.api.StructureScanner;
+import org.netbeans.modules.csl.core.Language;
+import org.netbeans.modules.csl.core.LanguageRegistry;
+import org.netbeans.modules.csl.spi.ParserResult;
+import org.netbeans.modules.parsing.api.ParserManager;
+import org.netbeans.modules.parsing.api.ResultIterator;
+import org.netbeans.modules.parsing.api.Source;
+import org.netbeans.modules.parsing.api.UserTask;
+import org.netbeans.modules.parsing.spi.ParseException;
+import org.netbeans.modules.parsing.spi.Parser;
+import org.openide.filesystems.FileObject;
+import org.openide.util.Exceptions;
+import org.springframework.boot.configurationmetadata.ConfigurationMetadataGroup;
+import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;
+import org.springframework.boot.configurationmetadata.ConfigurationMetadataSource;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+public class MicronautConfigUtilities {
+
+    public static ConfigurationMetadataProperty resolveProperty(Document doc, int offset, int[] span, List<ConfigurationMetadataSource> sources) {
+        LineDocument lineDocument = LineDocumentUtils.as(doc, LineDocument.class);
+        if (lineDocument != null) {
+            FileObject fo = EditorDocumentUtils.getFileObject(doc);
+            if (fo != null && "application.yml".equalsIgnoreCase(fo.getNameExt())) {
+                Project project = FileOwnerQuery.getOwner(fo);
+                if (project != null) {
+                    if (MicronautConfigProperties.hasConfigMetadata(project)) {
+                        try {
+                            int lineStart = LineDocumentUtils.getLineStart(lineDocument, offset);
+                            String text = lineDocument.getText(lineStart, offset - lineStart);
+                            if (!text.contains("#")) {
+                                int idx = text.indexOf(':');
+                                if (idx < 0) {
+                                    final ConfigurationMetadataProperty[] property = new ConfigurationMetadataProperty[]{null};
+                                    ParserManager.parse(Collections.singleton(Source.create(lineDocument)), new UserTask() {
+                                        public @Override void run(ResultIterator resultIterator) throws Exception {
+                                            Parser.Result r = resultIterator.getParserResult();
+                                            if (r instanceof ParserResult) {
+                                                Language language = LanguageRegistry.getInstance().getLanguageByMimeType(resultIterator.getSnapshot().getMimeType());
+                                                if (language != null) {
+                                                    StructureScanner scanner = language.getStructure();
+                                                    if (scanner != null) {
+                                                        List<? extends StructureItem> structures = scanner.scan((ParserResult) r);
+                                                        List<StructureItem> context = getContext(structures, offset);
+                                                        if (!context.isEmpty()) {
+                                                            StructureItem item = context.get(context.size() - 1);
+                                                            int start = (int) item.getPosition();
+                                                            int end = (int) item.getPosition() + item.getName().length();
+                                                            if (span != null && span.length == 2) {
+                                                                span[0] = start;
+                                                                span[1] = end;
+                                                            }
+                                                            if (start <= offset && offset <= end && item.getName().equals(lineDocument.getText(start, end - start))) {
+                                                                String propertyName = getPropertyName(context);
+                                                                for (Map.Entry<String, ConfigurationMetadataGroup> groupEntry : MicronautConfigProperties.getGroups(project).entrySet()) {
+                                                                    String groupKey = groupEntry.getKey();
+                                                                    if (Pattern.matches(groupKey.replaceAll("\\.", "\\\\.").replaceAll("\\*", "\\\\w*") + ".*", propertyName)) {
+                                                                        ConfigurationMetadataGroup group = groupEntry.getValue();
+                                                                        for (Map.Entry<String, ConfigurationMetadataProperty> propertyEntry : group.getProperties().entrySet()) {
+                                                                            String propertyKey = propertyEntry.getKey();
+                                                                            if (Pattern.matches(propertyKey.replaceAll("\\.", "\\\\.").replaceAll("\\*", "\\\\w*"), propertyName)) {
+                                                                                property[0] = propertyEntry.getValue();
+                                                                                if (sources != null) {
+                                                                                    sources.addAll(group.getSources().values());
+                                                                                }
+                                                                            }
+                                                                        }
+                                                                    }
+                                                                }
+                                                            }
+                                                        }
+                                                    }
+                                                }
+                                            }
+                                        }
+                                    });
+                                    return property[0];
+                                }
+                            }
+                        } catch (Exception ex) {
+                            Exceptions.printStackTrace(ex);
+                        }
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    public static void collectUsages(FileObject fo, String propertyName, Consumer<Usage> consumer) {
+        try {
+            ParserManager.parse(Collections.singleton(Source.create(fo)), new UserTask() {
+                public @Override void run(ResultIterator resultIterator) throws Exception {
+                    Parser.Result r = resultIterator.getParserResult();
+                    if (r instanceof ParserResult) {
+                        Language language = LanguageRegistry.getInstance().getLanguageByMimeType(resultIterator.getSnapshot().getMimeType());
+                        if (language != null) {
+                            StructureScanner scanner = language.getStructure();
+                            if (scanner != null) {
+                                find(fo, propertyName, scanner.scan((ParserResult) r), r.getSnapshot().getText(), consumer);
+                            }
+                        }
+                    }
+                }
+            });
+        } catch (ParseException ex) {
+            Exceptions.printStackTrace(ex);
+        }
+    }
+
+    private static void find(FileObject fo, String propertyName, List<? extends StructureItem> structures, CharSequence content, Consumer<Usage> consumer) {
+        int idx = propertyName.indexOf('.');
+        String name = idx < 0 ? propertyName : propertyName.substring(0, idx);
+        for (StructureItem structure : structures) {
+            if ("*".equals(name) || name.equals(structure.getName())) {
+                if (idx < 0) {
+                    int start = (int) structure.getPosition();
+                    int end = (int) structure.getEndPosition();
+                    String text = content.subSequence(start, end).toString();
+                    consumer.accept(new Usage(fo, start, end, text));
+                } else {
+                    find(fo, propertyName.substring(idx + 1), structure.getNestedItems(), content, consumer);
+                }
+            }
+        }
+    }
+
+    private static List<StructureItem> getContext(List<? extends StructureItem> structure, int offset) {
+        List<StructureItem> context = new ArrayList<>();
+        loop: while (structure != null && !structure.isEmpty()) {
+            for (StructureItem item : structure) {
+                if (item.getPosition() <= offset && offset <= item.getEndPosition()) {
+                    context.add(item);
+                    structure = item.getNestedItems();
+                    continue loop;
+                }
+            }
+            structure = null;
+        }
+        return context;
+    }
+
+    private static String getPropertyName(List<? extends StructureItem> context) {
+        StringBuilder sb = new StringBuilder();
+        for (StructureItem item : context) {
+            if (sb.length() > 0) {
+                sb.append('.');
+            }
+            sb.append(item.getName());
+        }
+        return sb.toString();
+    }
+
+    public static final class Usage {
+
+        private final FileObject fileObject;
+        private final int startOffset;
+        private final int endOffset;
+        private final String text;
+
+        public Usage(FileObject fileObject, int startOffset, int endOffset, String text) {
+            this.fileObject = fileObject;
+            this.startOffset = startOffset;
+            this.endOffset = endOffset;
+            this.text = text;
+        }
+
+        public FileObject getFileObject() {
+            return fileObject;
+        }
+
+        public int getStartOffset() {
+            return startOffset;
+        }
+
+        public int getEndOffset() {
+            return endOffset;
+        }
+
+        public String getText() {
+            return text;
+        }
+    }
+}
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionCollector.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionCollector.java
new file mode 100644
index 0000000..e9d9316
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionCollector.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.micronaut.completion;
+
+import java.util.function.Consumer;
+import javax.swing.text.Document;
+import org.netbeans.api.editor.document.EditorDocumentUtils;
+import org.netbeans.api.editor.mimelookup.MimeRegistration;
+import org.netbeans.api.lsp.Completion;
+import org.netbeans.api.project.FileOwnerQuery;
+import org.netbeans.api.project.Project;
+import org.netbeans.lib.editor.util.ArrayUtilities;
+import org.netbeans.modules.micronaut.MicronautConfigProperties;
+import org.netbeans.spi.lsp.CompletionCollector;
+import org.openide.filesystems.FileObject;
+import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+@MimeRegistration(mimeType = "text/x-yaml", service = CompletionCollector.class)
+public class MicronautConfigCompletionCollector implements CompletionCollector {
+
+    @Override
+    public boolean collectCompletions(Document doc, int offset, Completion.Context context, Consumer<Completion> consumer) {
+        FileObject fo = EditorDocumentUtils.getFileObject(doc);
+        if (fo != null && "application.yml".equalsIgnoreCase(fo.getNameExt())) {
+            Project project = FileOwnerQuery.getOwner(fo);
+            if (project != null) {
+                if (MicronautConfigProperties.hasConfigMetadata(project)) {
+                    new MicronautConfigCompletionTask().query(doc, offset, project, new MicronautConfigCompletionTask.ItemFactory<Completion>() {
+                        @Override
+                        public Completion createTopLevelPropertyItem(String propName, int offset, int baseIndent, int indentLevelSize) {
+                            StringBuilder insertText = new StringBuilder();
+                            Completion.TextFormat insertTextFormat = Completion.TextFormat.PlainText;
+                            if ("*".equals(propName)) {
+                                insertText.append("$1:\n");
+                                ArrayUtilities.appendSpaces(insertText, baseIndent + indentLevelSize);
+                                insertTextFormat = Completion.TextFormat.Snippet;
+                            } else {
+                                insertText.append(propName).append(":\n");
+                                ArrayUtilities.appendSpaces(insertText, indentLevelSize);
+                            }
+                            return CompletionCollector.newBuilder(propName).kind(Completion.Kind.Property).sortText(String.format("%4d%s", 10, propName))
+                                    .insertText(insertText.toString()).insertTextFormat(insertTextFormat).build();
+                        }
+
+                        @Override
+                        public Completion createPropertyItem(ConfigurationMetadataProperty property, int offset, int baseIndent, int indentLevelSize, int idx) {
+                            String[] parts = property.getId().substring(idx).split("\\.");
+                            StringBuilder insertText = new StringBuilder();
+                            int num = 1;
+                            int indent = 0;
+                            Completion.TextFormat insertTextFormat = Completion.TextFormat.PlainText;
+                            for (int i = 0; i < parts.length; i++) {
+                                String part = parts[i];
+                                if ("*".equals(part)) {
+                                    insertText.append("$" + num++);
+                                    insertTextFormat = Completion.TextFormat.Snippet;
+                                } else {
+                                    insertText.append(part);
+                                }
+                                if (i < parts.length - 1) {
+                                    insertText.append(":\n");
+                                    ArrayUtilities.appendSpaces(insertText, (indent = indent + indentLevelSize));
+                                } else {
+                                    insertText.append(": ");
+                                }
+                            }
+                            CompletionCollector.Builder builder = CompletionCollector.newBuilder(property.getId()).kind(Completion.Kind.Property)
+                                    .sortText(String.format("%4d%s", property.isDeprecated() ? 30 : 20, property.getId())).insertText(insertText.toString())
+                                    .insertTextFormat(insertTextFormat).documentation(new MicronautConfigDocumentation(property).getText());
+                            if (property.isDeprecated()) {
+                                builder.addTag(Completion.Tag.Deprecated);
+                            }
+                            return builder.build();
+                        }
+                    }).stream().forEach(consumer);
+                }
+            }
+        }
+        return true;
+    }
+}
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionItem.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionItem.java
new file mode 100644
index 0000000..e1a5648
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionItem.java
@@ -0,0 +1,302 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.micronaut.completion;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.util.regex.Pattern;
+import javax.swing.ImageIcon;
+import javax.swing.text.Document;
+import javax.swing.text.JTextComponent;
+import org.netbeans.api.editor.completion.Completion;
+import org.netbeans.api.editor.document.LineDocument;
+import org.netbeans.api.editor.document.LineDocumentUtils;
+import org.netbeans.lib.editor.codetemplates.api.CodeTemplateManager;
+import org.netbeans.lib.editor.util.ArrayUtilities;
+import org.netbeans.modules.editor.indent.api.IndentUtils;
+import org.netbeans.spi.editor.completion.CompletionItem;
+import org.netbeans.spi.editor.completion.CompletionTask;
+import org.netbeans.spi.editor.completion.support.CompletionUtilities;
+import org.netbeans.swing.plaf.LFCustoms;
+import org.openide.util.Exceptions;
+import org.openide.util.ImageUtilities;
+import org.openide.xml.XMLUtil;
+import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+public abstract class MicronautConfigCompletionItem implements CompletionItem {
+
+    public static final String PROPERTY_NAME_COLOR = getHTMLColor(64, 64, 217);
+    private static final String ICON = "org/netbeans/modules/editor/resources/completion/field_16.png"; //NOI18N
+
+    public static MicronautConfigCompletionItem createTopLevelPropertyItem(String propName, int offset, int baseIndent, int indentLevelSize) {
+        return new TopLevelItem(propName, offset, baseIndent, indentLevelSize);
+    }
+
+    public static MicronautConfigCompletionItem createPropertyItem(ConfigurationMetadataProperty property, int offset, int baseIndent, int indentLevelSize, int idx) {
+        return new PropertyItem(property, offset, baseIndent, indentLevelSize, idx);
+    }
+
+    protected final String propName;
+    protected final int offset;
+    protected final int baseIndent;
+    protected final int indentLevelSize;
+    private ImageIcon icon;
+
+    private MicronautConfigCompletionItem(String propName, int offset, int baseIndent, int indentLevelSize) {
+        this.propName = propName;
+        this.offset = offset;
+        this.baseIndent = baseIndent;
+        this.indentLevelSize = indentLevelSize;
+    }
+
+    @Override
+    public void defaultAction(JTextComponent component) {
+        if (component != null) {
+            Completion.get().hideDocumentation();
+            Completion.get().hideCompletion();
+            process(component, false);
+        }
+    }
+
+    @Override
+    public void processKeyEvent(KeyEvent evt) {
+        if (evt.getID() == KeyEvent.KEY_PRESSED && evt.getKeyCode() == KeyEvent.VK_ENTER && (evt.getModifiers() & InputEvent.CTRL_MASK) > 0) {
+            JTextComponent component = (JTextComponent)evt.getSource();
+            Completion.get().hideDocumentation();
+            Completion.get().hideCompletion();
+            process(component, true);
+            evt.consume();
+        }
+    }
+
+    @Override
+    public int getPreferredWidth(Graphics g, Font defaultFont) {
+        return CompletionUtilities.getPreferredWidth(getLeftHtmlText(), getRightHtmlText(), g, defaultFont);
+    }
+
+    @Override
+    public void render(Graphics g, Font defaultFont, Color defaultColor, Color backgroundColor, int width, int height, boolean selected) {
+        CompletionUtilities.renderHtml(getIcon(), getLeftHtmlText(), getRightHtmlText(), g, defaultFont, defaultColor, width, height, selected);
+    }
+
+    @Override
+    public CompletionTask createDocumentationTask() {
+        return null;
+    }
+
+    @Override
+    public CompletionTask createToolTipTask() {
+        return null;
+    }
+
+    @Override
+    public boolean instantSubstitution(JTextComponent component) {
+        return false;
+    }
+
+    @Override
+    public CharSequence getSortText() {
+        return propName;
+    }
+
+    @Override
+    public CharSequence getInsertPrefix() {
+        return propName;
+    }
+
+    protected String getLeftHtmlText() {
+        return null;
+    }
+
+    protected String getRightHtmlText() {
+        return null;
+    }
+
+    protected ImageIcon getIcon() {
+        if (icon == null) {
+            icon = ImageUtilities.loadImageIcon(ICON, false);
+        }
+        return icon;
+    }
+
+    protected abstract void process(JTextComponent component, boolean overwrite);
+
+    private static final class TopLevelItem extends MicronautConfigCompletionItem {
+
+        private TopLevelItem(String propName, int offset, int baseIndent, int indentLevelSize) {
+            super(propName, offset, baseIndent, indentLevelSize);
+        }
+
+        @Override
+        public int getSortPriority() {
+            return 10;
+        }
+
+        @Override
+        protected String getLeftHtmlText() {
+            return PROPERTY_NAME_COLOR + "<b>" + propName + "</b></font>";
+        }
+
+        @Override
+        protected void process(JTextComponent component, boolean overwrite) {
+            try {
+                Document doc = component.getDocument();
+                LineDocument lineDocument = LineDocumentUtils.as(doc, LineDocument.class);
+                if (lineDocument != null) {
+                    int caretOffset = component.getCaretPosition();
+                    int end = LineDocumentUtils.getWordEnd(lineDocument, caretOffset);
+                    if (overwrite && LineDocumentUtils.getWordStart(lineDocument, end) == offset) {
+                        if (doc.getText(end, 1).endsWith(":")) {
+                            end++;
+                        }
+                        doc.remove(offset, Math.max(caretOffset, end) - offset);
+                    } else if (offset < caretOffset) {
+                        doc.remove(offset, caretOffset - offset);
+                    }
+                    int lineStart = LineDocumentUtils.getLineStart(lineDocument, caretOffset);
+                    int lineIndent = IndentUtils.lineIndent(doc, lineStart);
+                    StringBuilder sb = new StringBuilder();
+                    ArrayUtilities.appendSpaces(sb, baseIndent - lineIndent);
+                    sb.append("*".equals(propName) ? "${PAR#1 default=\"\"}" : propName).append(":\n");
+                    ArrayUtilities.appendSpaces(sb, baseIndent + indentLevelSize);
+                    sb.append("${cursor completionInvoke}");
+                    CodeTemplateManager.get(doc).createTemporary(sb.toString()).insert(component);
+                }
+            } catch (Exception ex) {
+                Exceptions.printStackTrace(ex);
+            }
+        }
+    }
+
+    private static final class PropertyItem extends MicronautConfigCompletionItem {
+
+        private static final Pattern FQN = Pattern.compile("(\\w+\\.)+(\\w+)");
+        private final ConfigurationMetadataProperty property;
+        private final int idx;
+        private String left;
+        private String right;
+
+        private PropertyItem(ConfigurationMetadataProperty property, int offset, int baseIndent, int indentLevelSize, int idx) {
+            super(property.getId(), offset, baseIndent, indentLevelSize);
+            this.property = property;
+            this.idx = idx;
+        }
+
+        @Override
+        public CompletionTask createDocumentationTask() {
+            return MicronautConfigCompletionProvider.createDocTask(property);
+        }
+
+        @Override
+        public int getSortPriority() {
+            return property.isDeprecated() ? 30 : 20;
+        }
+
+        @Override
+        protected String getLeftHtmlText() {
+            if (left == null) {
+                if (property.isDeprecated()) {
+                    left = PROPERTY_NAME_COLOR + "<s>" + propName + "</s></font>";
+                } else {
+                    left = PROPERTY_NAME_COLOR + propName + "</font>";
+                }
+            }
+            return left;
+        }
+
+        @Override
+        protected String getRightHtmlText() {
+            if (right == null) {
+                String type = property.getType();
+                right = type != null ? escape(FQN.matcher(type).replaceAll("$2")) : "";
+            }
+            return right;
+        }
+
+        @Override
+        protected void process(JTextComponent component, boolean overwrite) {
+            try {
+                Document doc = component.getDocument();
+                LineDocument lineDocument = LineDocumentUtils.as(doc, LineDocument.class);
+                if (lineDocument != null) {
+                    int caretOffset = component.getCaretPosition();
+                    int end = LineDocumentUtils.getWordEnd(lineDocument, caretOffset);
+                    if (overwrite && LineDocumentUtils.getWordStart(lineDocument, end) == offset) {
+                        if (doc.getText(end, 1).endsWith(":")) {
+                            end++;
+                        }
+                        doc.remove(offset, Math.max(caretOffset, end) - offset);
+                    } else if (offset < caretOffset) {
+                        doc.remove(offset, caretOffset - offset);
+                    }
+                    int lineStart = LineDocumentUtils.getLineStart(lineDocument, caretOffset);
+                    int lineIndent = IndentUtils.lineIndent(doc, lineStart);
+                    StringBuilder sb = new StringBuilder();
+                    ArrayUtilities.appendSpaces(sb, baseIndent - lineIndent);
+                    String name = propName.substring(idx);
+                    int indent = baseIndent;
+                    final String[] parts = name.split("\\.");
+                    int num = 1;
+                    for (int i = 0; i < parts.length; i++) {
+                        String part = parts[i];
+                        if ("*".equals(part)) {
+                            sb.append("${PAR#" + num++ + " default=\"\"}");
+                        } else {
+                            sb.append(part);
+                        }
+                        if (i < parts.length - 1) {
+                            sb.append(":\n");
+                            ArrayUtilities.appendSpaces(sb, (indent = indent + indentLevelSize));
+                        } else {
+                            sb.append(": ${cursor}");
+                        }
+                    }
+                    CodeTemplateManager.get(doc).createTemporary(sb.toString()).insert(component);
+                }
+            } catch (Exception ex) {
+                Exceptions.printStackTrace(ex);
+            }
+        }
+    }
+
+    private static String getHTMLColor(int r, int g, int b) {
+        Color c = LFCustoms.shiftColor(new Color(r, g, b));
+        return "<font color=#" //NOI18N
+                + LFCustoms.getHexString(c.getRed())
+                + LFCustoms.getHexString(c.getGreen())
+                + LFCustoms.getHexString(c.getBlue())
+                + ">"; //NOI18N
+    }
+
+    private static String escape(String s) {
+        if (s != null) {
+            try {
+                return XMLUtil.toAttributeValue(s);
+            } catch (Exception ex) {}
+        }
+        return s;
+    }
+}
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionProvider.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionProvider.java
new file mode 100644
index 0000000..788e0da
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionProvider.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.micronaut.completion;
+
+import javax.swing.text.Document;
+import javax.swing.text.JTextComponent;
+import org.netbeans.api.editor.document.EditorDocumentUtils;
+import org.netbeans.api.editor.mimelookup.MimeRegistration;
+import org.netbeans.api.project.FileOwnerQuery;
+import org.netbeans.api.project.Project;
+import org.netbeans.modules.micronaut.MicronautConfigProperties;
+import org.netbeans.modules.micronaut.MicronautConfigUtilities;
+import org.netbeans.spi.editor.completion.CompletionProvider;
+import org.netbeans.spi.editor.completion.CompletionResultSet;
+import org.netbeans.spi.editor.completion.CompletionTask;
+import org.netbeans.spi.editor.completion.support.AsyncCompletionQuery;
+import org.netbeans.spi.editor.completion.support.AsyncCompletionTask;
+import org.openide.filesystems.FileObject;
+import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+@MimeRegistration(mimeType = "text/x-yaml", service = CompletionProvider.class)
+public class MicronautConfigCompletionProvider implements CompletionProvider {
+
+    @Override
+    public CompletionTask createTask(int queryType, JTextComponent component) {
+        FileObject fo = EditorDocumentUtils.getFileObject(component.getDocument());
+        if (fo != null && "application.yml".equalsIgnoreCase(fo.getNameExt())) {
+            Project project = FileOwnerQuery.getOwner(fo);
+            if (project != null) {
+                if (MicronautConfigProperties.hasConfigMetadata(project)) {
+                    switch (queryType) {
+                        case COMPLETION_ALL_QUERY_TYPE:
+                        case COMPLETION_QUERY_TYPE:
+                            return new AsyncCompletionTask(new MicronautConfigCompletionQuery(project), component);
+                        case DOCUMENTATION_QUERY_TYPE:
+                            return new AsyncCompletionTask(new MicronautConfigDocumentationQuery(null), component);
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public int getAutoQueryTypes(JTextComponent component, String typedText) {
+        return 0;
+    }
+
+    static CompletionTask createDocTask(ConfigurationMetadataProperty element) {
+        return new AsyncCompletionTask(new MicronautConfigDocumentationQuery(element));
+    }
+
+    private static class MicronautConfigCompletionQuery extends AsyncCompletionQuery {
+
+        private final Project project;
+
+        public MicronautConfigCompletionQuery(Project project) {
+            this.project = project;
+        }
+
+        @Override
+        protected void query(CompletionResultSet resultSet, Document doc, int caretOffset) {
+            resultSet.addAllItems(new MicronautConfigCompletionTask().query(doc, caretOffset, project, new MicronautConfigCompletionTask.ItemFactory<MicronautConfigCompletionItem>() {
+                @Override
+                public MicronautConfigCompletionItem createPropertyItem(ConfigurationMetadataProperty property, int offset, int baseIndent, int indentLevelSize, int idx) {
+                    resultSet.setAnchorOffset(offset);
+                    return MicronautConfigCompletionItem.createPropertyItem(property, offset, baseIndent, indentLevelSize, idx);
+                }
+
+                @Override
+                public MicronautConfigCompletionItem createTopLevelPropertyItem(String propName, int offset, int baseIndent, int indentLevelSize) {
+                    resultSet.setAnchorOffset(offset);
+                    return MicronautConfigCompletionItem.createTopLevelPropertyItem(propName, offset, baseIndent, indentLevelSize);
+                }
+            }));
+            resultSet.finish();
+        }
+    }
+
+    private static class MicronautConfigDocumentationQuery extends AsyncCompletionQuery {
+
+        private ConfigurationMetadataProperty element;
+
+        private MicronautConfigDocumentationQuery(ConfigurationMetadataProperty element) {
+            this.element = element;
+        }
+
+        @Override
+        protected void query(CompletionResultSet resultSet, Document doc, int caretOffset) {
+            if (element == null) {
+                element = MicronautConfigUtilities.resolveProperty(doc, caretOffset, null, null);
+            }
+            resultSet.setDocumentation(new MicronautConfigDocumentation(element));
+            resultSet.finish();
+        }
+    }
+}
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionTask.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionTask.java
new file mode 100644
index 0000000..4d6f914
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigCompletionTask.java
@@ -0,0 +1,207 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.micronaut.completion;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import org.netbeans.api.editor.document.LineDocument;
+import org.netbeans.api.editor.document.LineDocumentUtils;
+import org.netbeans.api.project.Project;
+import org.netbeans.modules.csl.api.StructureItem;
+import org.netbeans.modules.csl.api.StructureScanner;
+import org.netbeans.modules.csl.core.Language;
+import org.netbeans.modules.csl.core.LanguageRegistry;
+import org.netbeans.modules.csl.spi.ParserResult;
+import org.netbeans.modules.editor.indent.api.IndentUtils;
+import org.netbeans.modules.micronaut.MicronautConfigProperties;
+import org.netbeans.modules.parsing.api.ParserManager;
+import org.netbeans.modules.parsing.api.ResultIterator;
+import org.netbeans.modules.parsing.api.Source;
+import org.netbeans.modules.parsing.api.UserTask;
+import org.netbeans.modules.parsing.spi.Parser;
+import org.openide.util.Exceptions;
+import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+public class MicronautConfigCompletionTask {
+
+    public static interface ItemFactory<T> {
+        T createTopLevelPropertyItem(String propName, int offset, int baseIndent, int indentLevelSize);
+        T createPropertyItem(ConfigurationMetadataProperty property, int offset, int baseIndent, int indentLevelSize, int idx);
+    }
+
+    public <T> List<T> query(Document doc, int caretOffset, Project project, ItemFactory<T> factory) {
+        List<T> items = new ArrayList<>();
+        LineDocument lineDocument = LineDocumentUtils.as(doc, LineDocument.class);
+        if (lineDocument != null) {
+            int lineStart = LineDocumentUtils.getLineStart(lineDocument, caretOffset);
+            try {
+                String text = lineDocument.getText(lineStart, caretOffset - lineStart);
+                if (!text.contains("#")) {
+                    int idx = text.indexOf(':');
+                    if (idx < 0) {
+                        final int lineIndent = Math.min(IndentUtils.lineIndent(lineDocument, lineStart), caretOffset - lineStart);
+                        final int wordStart = LineDocumentUtils.getPreviousWhitespace(lineDocument, caretOffset) + 1;
+                        final String prefix = wordStart < caretOffset ? text.substring(wordStart - lineStart) : null;
+                        final int anchorOffset = wordStart < caretOffset ? wordStart : caretOffset;
+                        ParserManager.parse(Collections.singleton(Source.create(lineDocument)), new UserTask() {
+                            public @Override void run(ResultIterator resultIterator) throws Exception {
+                                Parser.Result r = resultIterator.getParserResult();
+                                if (r instanceof ParserResult) {
+                                    Language language = LanguageRegistry.getInstance().getLanguageByMimeType(resultIterator.getSnapshot().getMimeType());
+                                    if (language != null) {
+                                        StructureScanner scanner = language.getStructure();
+                                        if (scanner != null) {
+                                            List<? extends StructureItem> structures = scanner.scan((ParserResult) r);
+                                            int indentLevelSize = getIndentLevelSize(lineDocument, structures);
+                                            List<? extends StructureItem> context = getContext(structures, wordStart);
+                                            String filter = "";
+                                            StructureItem currentItem = null;
+                                            for (StructureItem item : context) {
+                                                int itemLineStart = LineDocumentUtils.getLineStart(lineDocument, (int) item.getPosition());
+                                                int itemLineIndent = IndentUtils.lineIndent(lineDocument, itemLineStart);
+                                                if (itemLineIndent < lineIndent) {
+                                                    filter += item.getName() + '.';
+                                                    currentItem = item;
+                                                }
+                                            }
+                                            int filterLength = filter.length();
+                                            if (prefix != null) {
+                                                filter += prefix;
+                                            }
+                                            int currentItemLineIndent = currentItem != null ? IndentUtils.lineIndent(lineDocument, LineDocumentUtils.getLineStart(lineDocument, (int) currentItem.getPosition())) : -indentLevelSize;
+                                            Map<String, ConfigurationMetadataProperty> properties = MicronautConfigProperties.getProperties(project);
+                                            Set<String> topLevels = new HashSet<>();
+                                            for (Map.Entry<String, ConfigurationMetadataProperty> entry : properties.entrySet()) {
+                                                String propName = entry.getKey();
+                                                int idx = match(propName, filter);
+                                                if (idx >= 0) {
+                                                    int dotIdx = propName.indexOf('.', idx);
+                                                    String simpleName = dotIdx < 0 ? propName.substring(idx) : propName.substring(idx, dotIdx);
+                                                    if (filter(currentItem != null ? currentItem.getNestedItems() : structures, simpleName)) {
+                                                        items.add(factory.createPropertyItem(entry.getValue(), anchorOffset, currentItemLineIndent + indentLevelSize, indentLevelSize, idx));
+                                                        if (dotIdx > 0) {
+                                                            topLevels.add(simpleName);
+                                                        }
+                                                    }
+                                                }
+                                            }
+                                            for (String topLevel : topLevels) {
+                                                items.add(factory.createTopLevelPropertyItem(topLevel, anchorOffset, currentItemLineIndent + indentLevelSize, indentLevelSize));
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        });
+                    }
+                }
+            } catch (Exception ex) {
+                Exceptions.printStackTrace(ex);
+            }
+        }
+        return items;
+    }
+
+    private int match(String propName, String filter) {
+        int len = 0;
+        String[] parts = propName.split("\\*");
+        for (int i = 0; i < parts.length; i++) {
+            String part = parts[i];
+            if (filter.length() <= part.length()) {
+                if (part.startsWith(filter)) {
+                    int idx = filter.lastIndexOf('.');
+                    return idx < 0 ? len : len + idx + 1;
+                } else {
+                    return -1;
+                }
+            }
+            if (i < parts.length - 1) {
+                if (!part.equals(filter.substring(0, part.length()))) {
+                    return -1;
+                }
+                len += part.length();
+                int idx = filter.indexOf('.', part.length());
+                if (idx < 0) {
+                    return -1;
+                }
+                len += 1;
+                filter = filter.substring(idx);
+            } else {
+                return filter.startsWith(part) ? len : -1;
+            }
+        }
+        return -1;
+    }
+
+    private boolean filter(List<? extends StructureItem> structures, String name) {
+        for (StructureItem item : structures) {
+            if (name.equals(item.getName())) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private List<StructureItem> getContext(List<? extends StructureItem> structure, int offset) {
+        List<StructureItem> items = new ArrayList<>();
+        while (structure != null && !structure.isEmpty()) {
+            StructureItem currentItem = null;
+            for (StructureItem item : structure) {
+                if (item.getPosition() < offset) {
+                    currentItem = item;
+                }
+            }
+            if (currentItem != null) {
+                items.add(currentItem);
+                structure = currentItem.getNestedItems();
+            } else {
+                structure = null;
+            }
+        }
+        return items;
+    }
+
+    private int getIndentLevelSize(LineDocument lineDocument, List<? extends StructureItem> structures) {
+        int indentLevel = IndentUtils.indentLevelSize(lineDocument);
+        try {
+            for (StructureItem structure : structures) {
+                int baseStart = LineDocumentUtils.getLineStart(lineDocument, (int) structure.getPosition());
+                int baseIndent = IndentUtils.lineIndent(lineDocument, baseStart);
+                for (StructureItem nestedItem : structure.getNestedItems()) {
+                    int lineStart = LineDocumentUtils.getLineStart(lineDocument, (int) nestedItem.getPosition());
+                    int lineIndent = IndentUtils.lineIndent(lineDocument, lineStart) - baseIndent;
+                    if (lineIndent > 0 && lineIndent < indentLevel) {
+                        indentLevel = lineIndent;
+                    }
+                }
+            }
+        } catch (BadLocationException ble) {}
+        return indentLevel;
+    }
+}
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigDocumentation.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigDocumentation.java
new file mode 100644
index 0000000..d003cce
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautConfigDocumentation.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.micronaut.completion;
+
+import java.net.URL;
+import javax.swing.Action;
+import org.netbeans.spi.editor.completion.CompletionDocumentation;
+import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;
+import org.springframework.boot.configurationmetadata.Deprecation;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+public class MicronautConfigDocumentation implements CompletionDocumentation {
+
+    private final ConfigurationMetadataProperty element;
+
+    MicronautConfigDocumentation(ConfigurationMetadataProperty element) {
+        this.element = element;
+    }
+
+    @Override
+    public String getText() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("<b>").append(makeNameLineBreakable(element.getId())).append("</b>");
+        String type = element.getType();
+        if (type != null) {
+            sb.append("<pre>").append(type).append("</pre>");
+        }
+        String description = element.getDescription();
+        String params = null;
+        if (description != null) {
+            int idx = description.indexOf("@param");
+            if (idx >= 0) {
+                params = description.substring(idx + 6).trim();
+                description = description.substring(0, idx).trim();
+            }
+            if (!description.isEmpty()) {
+                sb.append("<p>").append(description).append("</p>");
+            }
+        }
+        Deprecation deprecation = element.getDeprecation();
+        if (deprecation != null) {
+            sb.append("<p><b>Deprecated");
+            String reason = deprecation.getReason();
+            if (reason != null) {
+                sb.append(":</b> <i>").append(reason).append("</i>");
+            } else {
+                sb.append("</b>");
+            }
+            String replacement = deprecation.getReplacement();
+            if (replacement != null) {
+                sb.append("<br/>Replaced by: <code>").append(replacement).append("</code>");
+            }
+            sb.append("</p>");
+        }
+        if (params != null) {
+            sb.append("<p><b>Parameters:</b><blockquote>");
+            int idx = params.indexOf(' ');
+            if (idx < 0) {
+                sb.append(params).append("</p>");
+            } else {
+                sb.append("<code>").append(params.substring(0, idx)).append("</code>").append(params.substring(idx)).append("</blockquote></p>");
+            }
+        }
+        return sb.toString();
+    }
+
+    @Override
+    public URL getURL() {
+        return null;
+    }
+
+    @Override
+    public CompletionDocumentation resolveLink(String link) {
+        return null;
+    }
+
+    @Override
+    public Action getGotoSourceAction() {
+        return null;
+    }
+
+    private String makeNameLineBreakable(String name) {
+        return name.replace(".", /* ZERO WIDTH SPACE */".&#x200B;");
+    }
+}
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautJavaConfigPropertiesCompletion.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautJavaConfigPropertiesCompletion.java
new file mode 100644
index 0000000..085027c
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautJavaConfigPropertiesCompletion.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.micronaut.completion;
+
+import com.sun.source.util.TreePath;
+import com.sun.source.util.Trees;
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.processing.Completion;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.Processor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.TypeElement;
+import org.netbeans.api.project.FileOwnerQuery;
+import org.netbeans.api.project.Project;
+import org.netbeans.modules.micronaut.MicronautConfigProperties;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.URLMapper;
+import org.openide.util.Exceptions;
+import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+public class MicronautJavaConfigPropertiesCompletion implements Processor {
+
+    private static final Set<String> supportedAnnotationTypes = new HashSet<String>(Arrays.asList("io.micronaut.context.annotation.Property", "io.micronaut.context.annotation.Value"));
+    private Reference<ProcessingEnvironment> processingEnv;
+
+    @Override
+    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+        return false;
+    }
+
+    @Override
+    public Iterable<? extends Completion> getCompletions(Element element, AnnotationMirror annotation, ExecutableElement member, String userText) {
+        if (member != null && annotation != null) {
+            ProcessingEnvironment env = this.processingEnv.get();
+            if (env != null) {
+                Name annotationTypeSimpleName = annotation.getAnnotationType().asElement().getSimpleName();
+                String prefix = null;
+                String postfix = null;
+                if ("Property".contentEquals(annotationTypeSimpleName)) {
+                    if ("name".contentEquals(member.getSimpleName())) {
+                        prefix = "\"";
+                        postfix = prefix;
+                    }
+                } else if ("Value".contentEquals(annotationTypeSimpleName)) {
+                    prefix = "\"${";
+                    postfix = "}\"";
+                }
+                if (prefix != null && postfix != null) {
+                    Trees trees = Trees.instance(env);
+                    TreePath path = trees.getPath(element);
+                    if (path != null) {
+                        FileObject fo;
+                        try {
+                            fo = URLMapper.findFileObject(path.getCompilationUnit().getSourceFile().toUri().toURL());
+                        } catch (MalformedURLException ex) {
+                            Exceptions.printStackTrace(ex);
+                            return Collections.emptyList();
+                        }
+                        Project project = fo != null ? FileOwnerQuery.getOwner(fo) : null;
+                        if (project != null) {
+                            Map<String, ConfigurationMetadataProperty> properties = MicronautConfigProperties.getProperties(project);
+                            List<Completion> ret = new ArrayList<>(properties.size());
+                            String format = prefix + "%s" + postfix;
+                            for (ConfigurationMetadataProperty property : properties.values()) {
+                                if (!property.getId().contains("*")) {
+                                    ret.add(new Completion() {
+                                        @Override
+                                        public String getValue() {
+                                            return String.format(format, property.getId());
+                                        }
+                                        @Override
+                                        public String getMessage() {
+                                            return new MicronautConfigDocumentation(property).getText();
+                                        }
+                                    });
+                                }
+                            }
+                            return ret;
+                        }
+                    }
+                }
+            }
+        }
+        return Collections.emptyList();
+    }
+
+    @Override
+    public Set<String> getSupportedOptions() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public Set<String> getSupportedAnnotationTypes() {
+        return supportedAnnotationTypes;
+    }
+
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latest();
+    }
+
+    @Override
+    public void init(ProcessingEnvironment processingEnv) {
+        this.processingEnv = new WeakReference<ProcessingEnvironment>(processingEnv);
+    }
+}
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/hyperlink/MicronautConfigHyperlinkProvider.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/hyperlink/MicronautConfigHyperlinkProvider.java
new file mode 100644
index 0000000..bd77d7a
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/hyperlink/MicronautConfigHyperlinkProvider.java
@@ -0,0 +1,152 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.micronaut.hyperlink;
+
+import java.awt.Toolkit;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.atomic.AtomicBoolean;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.ElementFilter;
+import javax.swing.text.Document;
+import org.netbeans.api.editor.mimelookup.MimeRegistration;
+import org.netbeans.api.java.source.ClasspathInfo;
+import org.netbeans.api.java.source.ElementHandle;
+import org.netbeans.api.java.source.JavaSource;
+import org.netbeans.api.java.source.ui.ElementOpen;
+import org.netbeans.api.lsp.HyperlinkLocation;
+import org.netbeans.api.progress.BaseProgressUtils;
+import org.netbeans.lib.editor.hyperlink.spi.HyperlinkProviderExt;
+import org.netbeans.lib.editor.hyperlink.spi.HyperlinkType;
+import org.netbeans.modules.micronaut.MicronautConfigUtilities;
+import org.netbeans.spi.lsp.HyperlinkLocationProvider;
+import org.openide.util.NbBundle;
+import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;
+import org.springframework.boot.configurationmetadata.ConfigurationMetadataSource;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+@MimeRegistration(mimeType = "text/x-yaml", service = HyperlinkProviderExt.class, position = 1250)
+public class MicronautConfigHyperlinkProvider implements HyperlinkProviderExt {
+
+    @Override
+    public Set<HyperlinkType> getSupportedHyperlinkTypes() {
+        return EnumSet.of(HyperlinkType.GO_TO_DECLARATION);
+    }
+
+    @Override
+    public boolean isHyperlinkPoint(Document doc, int offset, HyperlinkType type) {
+        return getHyperlinkSpan(doc, offset, type) != null;
+    }
+
+    @Override
+    public int[] getHyperlinkSpan(Document doc, int offset, HyperlinkType type) {
+        int[] span = new int[2];
+        ConfigurationMetadataProperty property = MicronautConfigUtilities.resolveProperty(doc, offset, span, null);
+        return property != null ? span : null;
+    }
+
+    @Override
+    @NbBundle.Messages("LBL_GoToDeclaration=Go to Declaration")
+    public void performClickAction(Document doc, int offset, HyperlinkType type) {
+        AtomicBoolean cancel = new AtomicBoolean();
+        BaseProgressUtils.runOffEventDispatchThread(() -> {
+            List<ConfigurationMetadataSource> sources = new ArrayList<>();
+            ConfigurationMetadataProperty property = MicronautConfigUtilities.resolveProperty(doc, offset, null, sources);
+            if (property != null && !sources.isEmpty()) {
+                ClasspathInfo cpInfo = ClasspathInfo.create(doc);
+                ElementHandle handle = getElementHandle(cpInfo, sources.get(0).getType(), property.getName(), cancel);
+                if (handle == null || !ElementOpen.open(cpInfo, handle)) {
+                    Toolkit.getDefaultToolkit().beep();
+                }
+            }
+        }, Bundle.LBL_GoToDeclaration(), cancel, false);
+    }
+
+    @Override
+    public String getTooltipText(Document doc, int offset, HyperlinkType type) {
+        ConfigurationMetadataProperty property = MicronautConfigUtilities.resolveProperty(doc, offset, null, null);
+        if (property != null) {
+            StringBuilder sb = new StringBuilder("<html><body>");
+            sb.append("<b>").append(property.getId().replace(".", /* ZERO WIDTH SPACE */".&#x200B;")).append("</b>");
+            String propertyType = property.getType();
+            if (propertyType != null) {
+                sb.append("<pre>").append(propertyType).append("</pre>");
+            }
+            return sb.toString();
+        }
+        return null;
+    }
+
+    private static ElementHandle getElementHandle(ClasspathInfo cpInfo, String typeName, String propertyName, AtomicBoolean cancel) {
+        ElementHandle[] handle = new ElementHandle[1];
+        if (cpInfo != null) {
+            try {
+                JavaSource.create(cpInfo).runUserActionTask(controller -> {
+                    if (cancel != null && cancel.get()) {
+                        return;
+                    }
+                    handle[0] = ElementHandle.createTypeElementHandle(ElementKind.CLASS, typeName);
+                    TypeElement te = (TypeElement) handle[0].resolve(controller);
+                    if (te != null) {
+                        String name = "set" + propertyName.replaceAll("-", "");
+                        for (ExecutableElement executableElement : ElementFilter.methodsIn(te.getEnclosedElements())) {
+                            if (name.equalsIgnoreCase(executableElement.getSimpleName().toString())) {
+                                handle[0] = ElementHandle.create(executableElement);
+                                break;
+                            }
+                        }
+                    }
+                }, true);
+            } catch (IOException ex) {}
+        }
+        return handle[0];
+    }
+
+    @MimeRegistration(mimeType = "text/x-yaml", service = HyperlinkLocationProvider.class)
+    public static class LocationProvider implements HyperlinkLocationProvider {
+
+        @Override
+        public CompletableFuture<HyperlinkLocation> getHyperlinkLocation(Document doc, int offset) {
+            final AtomicBoolean cancel = new AtomicBoolean();
+            List<ConfigurationMetadataSource> sources = new ArrayList<>();
+            ConfigurationMetadataProperty property = MicronautConfigUtilities.resolveProperty(doc, offset, null, sources);
+            if (property != null && !sources.isEmpty()) {
+                ClasspathInfo cpInfo = ClasspathInfo.create(doc);
+                String typeName = sources.get(0).getType();
+                ElementHandle handle = getElementHandle(cpInfo, typeName, property.getName(), cancel);
+                if (handle != null) {
+                    CompletableFuture<ElementOpen.Location> future = ElementOpen.getLocation(cpInfo, handle, typeName.replace('.', '/') + ".class");
+                    return future.thenApply(location -> {
+                        return location != null ? HyperlinkLocationProvider.createHyperlinkLocation(location.getFileObject(), location.getStartOffset(), location.getEndOffset()) : null;
+                    });
+                }
+            }
+            return CompletableFuture.completedFuture(null);
+        }
+    }
+}
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/hyperlink/MicronautJavaHyperlinkProvider.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/hyperlink/MicronautJavaHyperlinkProvider.java
new file mode 100644
index 0000000..d79dc84
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/hyperlink/MicronautJavaHyperlinkProvider.java
@@ -0,0 +1,205 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.micronaut.hyperlink;
+
+import com.sun.source.tree.AnnotationTree;
+import com.sun.source.tree.AssignmentTree;
+import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.LiteralTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.util.SourcePositions;
+import com.sun.source.util.TreePath;
+import java.awt.Toolkit;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeKind;
+import javax.swing.text.Document;
+import org.netbeans.api.editor.document.EditorDocumentUtils;
+import org.netbeans.api.editor.mimelookup.MimeRegistration;
+import org.netbeans.api.java.project.JavaProjectConstants;
+import org.netbeans.api.java.source.JavaSource;
+import org.netbeans.api.java.source.TreeUtilities;
+import org.netbeans.api.lsp.HyperlinkLocation;
+import org.netbeans.api.project.FileOwnerQuery;
+import org.netbeans.api.project.Project;
+import org.netbeans.api.project.ProjectUtils;
+import org.netbeans.api.project.SourceGroup;
+import org.netbeans.lib.editor.hyperlink.spi.HyperlinkProviderExt;
+import org.netbeans.lib.editor.hyperlink.spi.HyperlinkType;
+import org.netbeans.modules.csl.api.UiUtils;
+import org.netbeans.modules.micronaut.MicronautConfigProperties;
+import org.netbeans.modules.micronaut.MicronautConfigUtilities;
+import org.netbeans.spi.lsp.HyperlinkLocationProvider;
+import org.openide.filesystems.FileObject;
+import org.openide.util.Exceptions;
+import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+@MimeRegistration(mimeType = "text/x-java", service = HyperlinkProviderExt.class, position = 1250)
+public class MicronautJavaHyperlinkProvider implements HyperlinkProviderExt {
+
+    private static final Pattern INJECT = Pattern.compile("\\$\\{(\\S+)(:\\S*)?}");
+
+    @Override
+    public Set<HyperlinkType> getSupportedHyperlinkTypes() {
+        return EnumSet.of(HyperlinkType.GO_TO_DECLARATION);
+    }
+
+    @Override
+    public boolean isHyperlinkPoint(Document doc, int offset, HyperlinkType type) {
+        return getHyperlinkSpan(doc, offset, type) != null;
+    }
+
+    @Override
+    public int[] getHyperlinkSpan(Document doc, int offset, HyperlinkType type) {
+        int[] span = new int[2];
+        MicronautConfigUtilities.Usage usage = resolve(doc, offset, span);
+        return usage != null ? span : null;
+    }
+
+    @Override
+    public void performClickAction(Document doc, int offset, HyperlinkType type) {
+        MicronautConfigUtilities.Usage usage = resolve(doc, offset, null);
+        if (usage == null || !UiUtils.open(usage.getFileObject(), usage.getStartOffset())) {
+            Toolkit.getDefaultToolkit().beep();
+        }
+    }
+
+    @Override
+    public String getTooltipText(Document doc, int offset, HyperlinkType type) {
+        MicronautConfigUtilities.Usage usage = resolve(doc, offset, null);
+        return usage != null ? usage.getText() : null;
+    }
+
+    private static MicronautConfigUtilities.Usage resolve(Document doc, int offset, int[] span) {
+        FileObject fo = EditorDocumentUtils.getFileObject(doc);
+        if (fo != null) {
+            Project project = FileOwnerQuery.getOwner(fo);
+            if (project != null) {
+                if (MicronautConfigProperties.hasConfigMetadata(project)) {
+                    SourceGroup[] sourceGroups = ProjectUtils.getSources(project).getSourceGroups(JavaProjectConstants.SOURCES_TYPE_RESOURCES);
+                    for (SourceGroup sourceGroup : sourceGroups) {
+                        FileObject rootFolder = sourceGroup.getRootFolder();
+                        FileObject cfgFo = rootFolder.getFileObject("application.yml");
+                        if (cfgFo != null) {
+                            JavaSource source = JavaSource.forDocument(doc);
+                            if (source != null) {
+                                try {
+                                    String propertyName = getPropertyName(doc, offset, span);
+                                    ConfigurationMetadataProperty property = MicronautConfigProperties.getProperties(project).get(propertyName);
+                                    if (property != null) {
+                                        List<MicronautConfigUtilities.Usage> usages = new ArrayList<>();
+                                        MicronautConfigUtilities.collectUsages(cfgFo, propertyName, usage -> {
+                                            usages.add(usage);
+                                        });
+                                        if (!usages.isEmpty()) {
+                                            return usages.get(0);
+                                        }
+                                    }
+                                } catch (Exception ex) {
+                                    Exceptions.printStackTrace(ex);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    private static String getPropertyName(Document doc, int offset, int[] span) throws IOException {
+        String[] ret = new String[1];
+        JavaSource source = JavaSource.forDocument(doc);
+        if (source != null) {
+            source.runUserActionTask(controller -> {
+                controller.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED);
+                TreeUtilities tu = controller.getTreeUtilities();
+                SourcePositions sp = controller.getTrees().getSourcePositions();
+                TreePath path = tu.pathFor(offset);
+                LiteralTree literal = null;
+                AnnotationTree annotation = null;
+                if (path.getLeaf().getKind() == Tree.Kind.STRING_LITERAL) {
+                    literal = (LiteralTree) path.getLeaf();
+                    TreePath annPath = tu.getPathElementOfKind(Tree.Kind.ANNOTATION, path);
+                    annotation = annPath != null ? (AnnotationTree) annPath.getLeaf() : null;
+                } else if (path.getLeaf().getKind() == Tree.Kind.ANNOTATION) {
+                    annotation = (AnnotationTree) path.getLeaf();
+                    for (ExpressionTree arg : annotation.getArguments()) {
+                        if (arg.getKind() == Tree.Kind.ASSIGNMENT) {
+                            ExpressionTree expression = ((AssignmentTree) arg).getExpression();
+                            if (expression.getKind() == Tree.Kind.STRING_LITERAL && sp.getStartPosition(path.getCompilationUnit(), expression) < offset && sp.getEndPosition(path.getCompilationUnit(), expression) >= offset) {
+                                literal = (LiteralTree) expression;
+                            }
+                        }
+                    }
+                }
+                if (literal != null && annotation != null) {
+                    Element el = controller.getTrees().getElement(new TreePath(path, annotation.getAnnotationType()));
+                    if (el != null && el.asType().getKind() == TypeKind.DECLARED) {
+                        Name name = ((TypeElement)((DeclaredType)el.asType()).asElement()).getQualifiedName();
+                        if ("io.micronaut.context.annotation.Property".contentEquals(name)) {
+                            ret[0] = (String) literal.getValue();
+                            if (span != null) {
+                                span[0] = (int) sp.getStartPosition(path.getCompilationUnit(), literal) + 1;
+                                span[1] = (int) sp.getEndPosition(path.getCompilationUnit(), literal) - 1;
+                            }
+                        } else if ("io.micronaut.context.annotation.Value".contentEquals(name)) {
+                            String value = (String) literal.getValue();
+                            Matcher matcher = INJECT.matcher(value);
+                            if (matcher.find()) {
+                                ret[0] = matcher.group(1);
+                                if (span != null) {
+                                    span[0] = (int) sp.getStartPosition(path.getCompilationUnit(), literal) + matcher.start(1) + 1;
+                                    span[1] = (int) sp.getStartPosition(path.getCompilationUnit(), literal) + matcher.end(1) + 1;
+                                }
+                            }
+                        }
+                    }
+                }
+            }, true);
+        }
+        return ret[0];
+    }
+
+    @MimeRegistration(mimeType = "text/x-java", service = HyperlinkLocationProvider.class)
+    public static class LocationProvider implements HyperlinkLocationProvider {
+
+        @Override
+        public CompletableFuture<HyperlinkLocation> getHyperlinkLocation(Document doc, int offset) {
+            MicronautConfigUtilities.Usage usage = resolve(doc, offset, null);
+            return CompletableFuture.completedFuture(usage != null
+                    ? HyperlinkLocationProvider.createHyperlinkLocation(usage.getFileObject(), usage.getStartOffset(), usage.getEndOffset())
+                    : null);
+        }
+    }
+}
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/BasePropertiesVisual.form b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/BasePropertiesVisual.form
new file mode 100644
index 0000000..f9546a8
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/BasePropertiesVisual.form
@@ -0,0 +1,348 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+
+<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+  <NonVisualComponents>
+    <Component class="javax.swing.ButtonGroup" name="serviceButtonGroup">
+    </Component>
+    <Component class="javax.swing.ButtonGroup" name="languageButtonGroup">
+    </Component>
+  </NonVisualComponents>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Component id="serviceURLLabel" min="-2" max="-2" attributes="0"/>
+                  <Group type="102" attributes="0">
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Component id="javaVersionLabel" alignment="0" min="-2" max="-2" attributes="0"/>
+                          <Component id="groupLabel" alignment="0" min="-2" max="-2" attributes="0"/>
+                          <Component id="languageLabel" alignment="0" min="-2" max="-2" attributes="0"/>
+                          <Component id="customRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
+                          <Component id="artifactLabel" alignment="0" min="-2" max="-2" attributes="0"/>
+                          <Component id="applicationTypeLabel" alignment="0" min="-2" pref="90" max="-2" attributes="0"/>
+                          <Component id="versionLabel" alignment="0" min="-2" max="-2" attributes="0"/>
+                          <Component id="snapshotRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
+                          <Component id="defaultRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Component id="defaultURLLabel" max="32767" attributes="0"/>
+                          <Component id="versionTextField" pref="566" max="32767" attributes="0"/>
+                          <Component id="snapshotURLLabel" alignment="0" max="32767" attributes="0"/>
+                          <Component id="customTextField" alignment="0" max="32767" attributes="0"/>
+                          <Component id="applicationTypeComboBox" alignment="1" max="32767" attributes="0"/>
+                          <Component id="artifactTextField" alignment="1" max="32767" attributes="0"/>
+                          <Component id="groupTextField" max="32767" attributes="0"/>
+                          <Group type="102" attributes="0">
+                              <Group type="103" groupAlignment="0" attributes="0">
+                                  <Component id="javaVersionComboBox" min="-2" pref="63" max="-2" attributes="0"/>
+                                  <Group type="102" alignment="0" attributes="0">
+                                      <Component id="javaRadioButton" min="-2" pref="50" max="-2" attributes="0"/>
+                                      <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                                      <Component id="kotlinRadioButton" min="-2" max="-2" attributes="0"/>
+                                      <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                                      <Component id="groovyRadioButton" min="-2" max="-2" attributes="0"/>
+                                  </Group>
+                              </Group>
+                              <EmptySpace min="0" pref="0" max="32767" attributes="0"/>
+                          </Group>
+                      </Group>
+                  </Group>
+              </Group>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="1" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="serviceURLLabel" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="defaultRadioButton" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="defaultURLLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="snapshotRadioButton" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="snapshotURLLabel" alignment="0" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="customRadioButton" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="customTextField" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="versionTextField" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="versionLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace type="separate" max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="groupTextField" alignment="3" min="-2" pref="19" max="-2" attributes="0"/>
+                  <Component id="groupLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="artifactTextField" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="artifactLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace type="separate" max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="applicationTypeComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="applicationTypeLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="javaVersionComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="javaVersionLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace min="-2" pref="4" max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="languageLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="javaRadioButton" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="kotlinRadioButton" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="groovyRadioButton" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace pref="36" max="32767" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Component class="javax.swing.JLabel" name="serviceURLLabel">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/netbeans/modules/micronaut/newproject/Bundle.properties" key="LBL_ChooseServiceURL" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JRadioButton" name="defaultRadioButton">
+      <Properties>
+        <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
+          <ComponentRef name="serviceButtonGroup"/>
+        </Property>
+        <Property name="selected" type="boolean" value="true"/>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/netbeans/modules/micronaut/newproject/Bundle.properties" key="LBL_Default" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+        <Property name="actionCommand" type="java.lang.String" value="DEFAULT"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="defaultURLLabel">
+      <Properties>
+        <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
+          <Font name="Dialog" size="12" style="2"/>
+        </Property>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+          <Connection code="MicronautLaunchService.defaultURL" type="code"/>
+        </Property>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JRadioButton" name="snapshotRadioButton">
+      <Properties>
+        <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
+          <ComponentRef name="serviceButtonGroup"/>
+        </Property>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/netbeans/modules/micronaut/newproject/Bundle.properties" key="LBL_Snapshot" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+        <Property name="actionCommand" type="java.lang.String" value="SNAPSHOT"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="snapshotURLLabel">
+      <Properties>
+        <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
+          <Font name="Dialog" size="12" style="2"/>
+        </Property>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+          <Connection code="MicronautLaunchService.snapshotURL" type="code"/>
+        </Property>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JRadioButton" name="customRadioButton">
+      <Properties>
+        <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
+          <ComponentRef name="serviceButtonGroup"/>
+        </Property>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/netbeans/modules/micronaut/newproject/Bundle.properties" key="LBL_Custom" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+        <Property name="actionCommand" type="java.lang.String" value="CUSTOM"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JTextField" name="customTextField">
+    </Component>
+    <Component class="javax.swing.JLabel" name="versionLabel">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/netbeans/modules/micronaut/newproject/Bundle.properties" key="LBL_Version" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JTextField" name="versionTextField">
+      <Properties>
+        <Property name="editable" type="boolean" value="false"/>
+        <Property name="columns" type="int" value="20"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="groupLabel">
+      <Properties>
+        <Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
+          <ComponentRef name="groupTextField"/>
+        </Property>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/netbeans/modules/micronaut/newproject/Bundle.properties" key="LBL_Group" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+      <AuxValues>
+        <AuxValue name="generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
+      </AuxValues>
+    </Component>
+    <Component class="javax.swing.JTextField" name="groupTextField">
+      <Properties>
+        <Property name="columns" type="int" value="20"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="artifactLabel">
+      <Properties>
+        <Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
+          <ComponentRef name="artifactTextField"/>
+        </Property>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/netbeans/modules/micronaut/newproject/Bundle.properties" key="LBL_Artifact" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+      <AuxValues>
+        <AuxValue name="generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
+      </AuxValues>
+    </Component>
+    <Component class="javax.swing.JTextField" name="artifactTextField">
+      <Properties>
+        <Property name="editable" type="boolean" value="false"/>
+        <Property name="columns" type="int" value="20"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="applicationTypeLabel">
+      <Properties>
+        <Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
+          <ComponentRef name="applicationTypeComboBox"/>
+        </Property>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/netbeans/modules/micronaut/newproject/Bundle.properties" key="LBL_ApplicationType" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JComboBox" name="applicationTypeComboBox">
+      <AuxValues>
+        <AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;MicronautLaunchService.ApplicationType&gt;"/>
+      </AuxValues>
+    </Component>
+    <Component class="javax.swing.JLabel" name="javaVersionLabel">
+      <Properties>
+        <Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
+          <ComponentRef name="javaVersionComboBox"/>
+        </Property>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/netbeans/modules/micronaut/newproject/Bundle.properties" key="LBL_JavaVersion" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JComboBox" name="javaVersionComboBox">
+      <Properties>
+        <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
+          <StringArray count="8">
+            <StringItem index="0" value="8"/>
+            <StringItem index="1" value="9"/>
+            <StringItem index="2" value="10"/>
+            <StringItem index="3" value="11"/>
+            <StringItem index="4" value="12"/>
+            <StringItem index="5" value="13"/>
+            <StringItem index="6" value="14"/>
+            <StringItem index="7" value="15"/>
+          </StringArray>
+        </Property>
+      </Properties>
+      <AuxValues>
+        <AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
+      </AuxValues>
+    </Component>
+    <Component class="javax.swing.JLabel" name="languageLabel">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/netbeans/modules/micronaut/newproject/Bundle.properties" key="LBL_Language" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JRadioButton" name="javaRadioButton">
+      <Properties>
+        <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
+          <ComponentRef name="languageButtonGroup"/>
+        </Property>
+        <Property name="selected" type="boolean" value="true"/>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/netbeans/modules/micronaut/newproject/Bundle.properties" key="LBL_Java" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+        <Property name="actionCommand" type="java.lang.String" value="JAVA"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JRadioButton" name="kotlinRadioButton">
+      <Properties>
+        <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
+          <ComponentRef name="languageButtonGroup"/>
+        </Property>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/netbeans/modules/micronaut/newproject/Bundle.properties" key="LBL_Kotlin" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+        <Property name="actionCommand" type="java.lang.String" value="KOTLIN"/>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JRadioButton" name="groovyRadioButton">
+      <Properties>
+        <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
+          <ComponentRef name="languageButtonGroup"/>
+        </Property>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/netbeans/modules/micronaut/newproject/Bundle.properties" key="LBL_Groovy" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+        <Property name="actionCommand" type="java.lang.String" value="GROOVY"/>
+      </Properties>
+    </Component>
+  </SubComponents>
+</Form>
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/BasePropertiesVisual.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/BasePropertiesVisual.java
new file mode 100644
index 0000000..31674cb
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/BasePropertiesVisual.java
@@ -0,0 +1,424 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.micronaut.newproject;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+import java.net.MalformedURLException;
+import java.net.URL;
+import javax.lang.model.SourceVersion;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import org.openide.WizardDescriptor;
+import org.openide.WizardValidationException;
+import org.openide.util.AsyncGUIJob;
+import org.openide.util.RequestProcessor;
+
+/**
+ * Options panel for the Base Properties step in Micronaut project wizard.
+ *
+ * @author Dusan Balek
+ */
+public class BasePropertiesVisual extends JPanel implements DocumentListener, ActionListener, AsyncGUIJob {
+
+    private final BasePropertiesWizardPanel panel;
+    private boolean initialized = false;
+    private boolean failed = false;
+
+    public BasePropertiesVisual(BasePropertiesWizardPanel panel) {
+        initComponents();
+        this.panel = panel;
+        this.defaultRadioButton.addActionListener(this);
+        this.snapshotRadioButton.addActionListener(this);
+        this.customRadioButton.addActionListener(this);
+        this.customTextField.getDocument().addDocumentListener(this);
+        this.groupTextField.getDocument().addDocumentListener(this);
+        this.versionTextField.getDocument().addDocumentListener(this);
+        this.customTextField.addFocusListener(new FocusAdapter() {
+            @Override
+            public void focusGained(FocusEvent e) {
+                customRadioButton.setSelected(true);
+                versionTextField.setText("");
+                applicationTypeComboBox.removeAllItems();
+            }
+            @Override
+            public void focusLost(FocusEvent e) {
+                if (customRadioButton.isSelected()) {
+                    if (customURLValid()) {
+                        refresh();
+                    } else {
+                        panel.fireChangeEvent();
+                    }
+                }
+            }
+        });
+    }
+
+    /**
+     * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of
+     * this method is always regenerated by the Form Editor.
+     */
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        serviceButtonGroup = new javax.swing.ButtonGroup();
+        languageButtonGroup = new javax.swing.ButtonGroup();
+        serviceURLLabel = new javax.swing.JLabel();
+        defaultRadioButton = new javax.swing.JRadioButton();
+        defaultURLLabel = new javax.swing.JLabel();
+        snapshotRadioButton = new javax.swing.JRadioButton();
+        snapshotURLLabel = new javax.swing.JLabel();
+        customRadioButton = new javax.swing.JRadioButton();
+        customTextField = new javax.swing.JTextField();
+        versionLabel = new javax.swing.JLabel();
+        versionTextField = new javax.swing.JTextField();
+        groupLabel = new javax.swing.JLabel();
+        groupTextField = new javax.swing.JTextField();
+        artifactLabel = new javax.swing.JLabel();
+        artifactTextField = new javax.swing.JTextField();
+        applicationTypeLabel = new javax.swing.JLabel();
+        applicationTypeComboBox = new javax.swing.JComboBox<>();
+        javaVersionLabel = new javax.swing.JLabel();
+        javaVersionComboBox = new javax.swing.JComboBox<>();
+        languageLabel = new javax.swing.JLabel();
+        javaRadioButton = new javax.swing.JRadioButton();
+        kotlinRadioButton = new javax.swing.JRadioButton();
+        groovyRadioButton = new javax.swing.JRadioButton();
+
+        org.openide.awt.Mnemonics.setLocalizedText(serviceURLLabel, org.openide.util.NbBundle.getMessage(BasePropertiesVisual.class, "LBL_ChooseServiceURL")); // NOI18N
+
+        serviceButtonGroup.add(defaultRadioButton);
+        defaultRadioButton.setSelected(true);
+        org.openide.awt.Mnemonics.setLocalizedText(defaultRadioButton, org.openide.util.NbBundle.getMessage(BasePropertiesVisual.class, "LBL_Default")); // NOI18N
+        defaultRadioButton.setActionCommand("DEFAULT");
+
+        defaultURLLabel.setFont(new java.awt.Font("Dialog", 2, 12)); // NOI18N
+        org.openide.awt.Mnemonics.setLocalizedText(defaultURLLabel, MicronautLaunchService.defaultURL);
+
+        serviceButtonGroup.add(snapshotRadioButton);
+        org.openide.awt.Mnemonics.setLocalizedText(snapshotRadioButton, org.openide.util.NbBundle.getMessage(BasePropertiesVisual.class, "LBL_Snapshot")); // NOI18N
+        snapshotRadioButton.setActionCommand("SNAPSHOT");
+
+        snapshotURLLabel.setFont(new java.awt.Font("Dialog", 2, 12)); // NOI18N
+        org.openide.awt.Mnemonics.setLocalizedText(snapshotURLLabel, MicronautLaunchService.snapshotURL);
+
+        serviceButtonGroup.add(customRadioButton);
+        org.openide.awt.Mnemonics.setLocalizedText(customRadioButton, org.openide.util.NbBundle.getMessage(BasePropertiesVisual.class, "LBL_Custom")); // NOI18N
+        customRadioButton.setActionCommand("CUSTOM");
+
+        org.openide.awt.Mnemonics.setLocalizedText(versionLabel, org.openide.util.NbBundle.getMessage(BasePropertiesVisual.class, "LBL_Version")); // NOI18N
+
+        versionTextField.setEditable(false);
+        versionTextField.setColumns(20);
+
+        groupLabel.setLabelFor(groupTextField);
+        org.openide.awt.Mnemonics.setLocalizedText(groupLabel, org.openide.util.NbBundle.getMessage(BasePropertiesVisual.class, "LBL_Group")); // NOI18N
+
+        groupTextField.setColumns(20);
+
+        artifactLabel.setLabelFor(artifactTextField);
+        org.openide.awt.Mnemonics.setLocalizedText(artifactLabel, org.openide.util.NbBundle.getMessage(BasePropertiesVisual.class, "LBL_Artifact")); // NOI18N
+
+        artifactTextField.setEditable(false);
+        artifactTextField.setColumns(20);
+
+        applicationTypeLabel.setLabelFor(applicationTypeComboBox);
+        org.openide.awt.Mnemonics.setLocalizedText(applicationTypeLabel, org.openide.util.NbBundle.getMessage(BasePropertiesVisual.class, "LBL_ApplicationType")); // NOI18N
+
+        javaVersionLabel.setLabelFor(javaVersionComboBox);
+        org.openide.awt.Mnemonics.setLocalizedText(javaVersionLabel, org.openide.util.NbBundle.getMessage(BasePropertiesVisual.class, "LBL_JavaVersion")); // NOI18N
+
+        javaVersionComboBox.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "8", "9", "10", "11", "12", "13", "14", "15" }));
+
+        org.openide.awt.Mnemonics.setLocalizedText(languageLabel, org.openide.util.NbBundle.getMessage(BasePropertiesVisual.class, "LBL_Language")); // NOI18N
+
+        languageButtonGroup.add(javaRadioButton);
+        javaRadioButton.setSelected(true);
+        org.openide.awt.Mnemonics.setLocalizedText(javaRadioButton, org.openide.util.NbBundle.getMessage(BasePropertiesVisual.class, "LBL_Java")); // NOI18N
+        javaRadioButton.setActionCommand("JAVA");
+
+        languageButtonGroup.add(kotlinRadioButton);
+        org.openide.awt.Mnemonics.setLocalizedText(kotlinRadioButton, org.openide.util.NbBundle.getMessage(BasePropertiesVisual.class, "LBL_Kotlin")); // NOI18N
+        kotlinRadioButton.setActionCommand("KOTLIN");
+
+        languageButtonGroup.add(groovyRadioButton);
+        org.openide.awt.Mnemonics.setLocalizedText(groovyRadioButton, org.openide.util.NbBundle.getMessage(BasePropertiesVisual.class, "LBL_Groovy")); // NOI18N
+        groovyRadioButton.setActionCommand("GROOVY");
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+        this.setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(serviceURLLabel)
+                    .addGroup(layout.createSequentialGroup()
+                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                            .addComponent(javaVersionLabel)
+                            .addComponent(groupLabel)
+                            .addComponent(languageLabel)
+                            .addComponent(customRadioButton)
+                            .addComponent(artifactLabel)
+                            .addComponent(applicationTypeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE)
+                            .addComponent(versionLabel)
+                            .addComponent(snapshotRadioButton)
+                            .addComponent(defaultRadioButton))
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                            .addComponent(defaultURLLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                            .addComponent(versionTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 566, Short.MAX_VALUE)
+                            .addComponent(snapshotURLLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                            .addComponent(customTextField)
+                            .addComponent(applicationTypeComboBox, javax.swing.GroupLayout.Alignment.TRAILING, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                            .addComponent(artifactTextField, javax.swing.GroupLayout.Alignment.TRAILING)
+                            .addComponent(groupTextField)
+                            .addGroup(layout.createSequentialGroup()
+                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                                    .addComponent(javaVersionComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 63, javax.swing.GroupLayout.PREFERRED_SIZE)
+                                    .addGroup(layout.createSequentialGroup()
+                                        .addComponent(javaRadioButton, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)
+                                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                                        .addComponent(kotlinRadioButton)
+                                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                                        .addComponent(groovyRadioButton)))
+                                .addGap(0, 0, Short.MAX_VALUE)))))
+                .addContainerGap())
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(serviceURLLabel)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(defaultRadioButton)
+                    .addComponent(defaultURLLabel))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(snapshotRadioButton)
+                    .addComponent(snapshotURLLabel))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(customRadioButton)
+                    .addComponent(customTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(versionTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(versionLabel))
+                .addGap(18, 18, 18)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(groupTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 19, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(groupLabel))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(artifactTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(artifactLabel))
+                .addGap(18, 18, 18)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(applicationTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(applicationTypeLabel))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(javaVersionComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(javaVersionLabel))
+                .addGap(4, 4, 4)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(languageLabel)
+                    .addComponent(javaRadioButton)
+                    .addComponent(kotlinRadioButton)
+                    .addComponent(groovyRadioButton))
+                .addContainerGap(36, Short.MAX_VALUE))
+        );
+    }// </editor-fold>//GEN-END:initComponents
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JComboBox<MicronautLaunchService.ApplicationType> applicationTypeComboBox;
+    private javax.swing.JLabel applicationTypeLabel;
+    private javax.swing.JLabel artifactLabel;
+    private javax.swing.JTextField artifactTextField;
+    private javax.swing.JRadioButton customRadioButton;
+    private javax.swing.JTextField customTextField;
+    private javax.swing.JRadioButton defaultRadioButton;
+    private javax.swing.JLabel defaultURLLabel;
+    private javax.swing.JRadioButton groovyRadioButton;
+    private javax.swing.JLabel groupLabel;
+    private javax.swing.JTextField groupTextField;
+    private javax.swing.JRadioButton javaRadioButton;
+    private javax.swing.JComboBox<String> javaVersionComboBox;
+    private javax.swing.JLabel javaVersionLabel;
+    private javax.swing.JRadioButton kotlinRadioButton;
+    private javax.swing.ButtonGroup languageButtonGroup;
+    private javax.swing.JLabel languageLabel;
+    private javax.swing.ButtonGroup serviceButtonGroup;
+    private javax.swing.JLabel serviceURLLabel;
+    private javax.swing.JRadioButton snapshotRadioButton;
+    private javax.swing.JLabel snapshotURLLabel;
+    private javax.swing.JLabel versionLabel;
+    private javax.swing.JTextField versionTextField;
+    // End of variables declaration//GEN-END:variables
+
+    boolean valid(WizardDescriptor wizardDescriptor) {
+        if (failed) {
+            wizardDescriptor.putProperty(WizardDescriptor.PROP_ERROR_MESSAGE, "Problems in contacting service!");
+            return false;
+        }
+        if (groupTextField.getText().isEmpty()) {
+            wizardDescriptor.putProperty(WizardDescriptor.PROP_ERROR_MESSAGE, "Group can't be empty.");
+            return false;
+        }
+        if (!SourceVersion.isName(groupTextField.getText())) {
+            wizardDescriptor.putProperty(WizardDescriptor.PROP_ERROR_MESSAGE, "Not a valid Group name.");
+            return false;
+        }
+        if (customRadioButton.isSelected()) {
+            if (customTextField.getText().isEmpty()) {
+                wizardDescriptor.putProperty(WizardDescriptor.PROP_ERROR_MESSAGE, "Service URL can't be empty.");
+                return false;
+            }
+            if (!customURLValid()) {
+                wizardDescriptor.putProperty(WizardDescriptor.PROP_ERROR_MESSAGE, "Not a valid Service URL.");
+                return false;
+            }
+        }
+        wizardDescriptor.putProperty(WizardDescriptor.PROP_ERROR_MESSAGE, "");
+        return !versionTextField.getText().isEmpty();
+    }
+
+    void store(WizardDescriptor wd) {
+        wd.putProperty(MicronautProjectWizardIterator.SERVICE_URL, getServiceUrl());
+        wd.putProperty(MicronautProjectWizardIterator.MAVEN_GROUP, groupTextField.getText().trim());
+        wd.putProperty(MicronautProjectWizardIterator.APPLICATION_TYPE, applicationTypeComboBox.getSelectedItem());
+        wd.putProperty(MicronautProjectWizardIterator.JAVA_VERSION, javaVersionComboBox.getSelectedItem());
+        wd.putProperty(MicronautProjectWizardIterator.LANGUAGE, languageButtonGroup.getSelection().getActionCommand());
+    }
+
+    void read(WizardDescriptor wd) {
+        String serviceUrl = (String) wd.getProperty(MicronautProjectWizardIterator.SERVICE_URL);
+        if (serviceUrl != null) {
+            switch (serviceUrl) {
+                case MicronautLaunchService.defaultURL:
+                    this.defaultRadioButton.setSelected(true);
+                    break;
+                case MicronautLaunchService.snapshotURL:
+                    this.snapshotRadioButton.setSelected(true);
+                    break;
+                default:
+                    this.customTextField.setText(serviceUrl);
+            }
+        }
+        String group = (String) wd.getProperty(MicronautProjectWizardIterator.MAVEN_GROUP);
+        this.groupTextField.setText(group == null || group.isEmpty() ? "com.example" : group);
+        this.artifactTextField.setText((String) wd.getProperty(MicronautProjectWizardIterator.MAVEN_ARTIFACT));
+        javaVersionComboBox.setSelectedItem(MicronautProjectWizardIterator.JAVA_VERSION);
+        applicationTypeComboBox.setSelectedItem(wd.getProperty(MicronautProjectWizardIterator.APPLICATION_TYPE));
+    }
+
+    void validate(WizardDescriptor d) throws WizardValidationException {
+        // nothing to validate
+    }
+
+    @Override
+    public void insertUpdate(DocumentEvent e) {
+        panel.fireChangeEvent();
+    }
+
+    @Override
+    public void removeUpdate(DocumentEvent e) {
+        panel.fireChangeEvent();
+    }
+
+    @Override
+    public void changedUpdate(DocumentEvent e) {
+        panel.fireChangeEvent();
+    }
+
+    @Override
+    public void construct() {
+        try {
+            panel.wizardDescriptor.putProperty(WizardDescriptor.PROP_INFO_MESSAGE, "Contacting service...");
+            MicronautLaunchService service = MicronautLaunchService.getInstance();
+            String serviceUrl = getServiceUrl();
+            String micronautVersion = service.getMicronautVersion(serviceUrl);
+            for (MicronautLaunchService.ApplicationType type : service.getApplicationTypes(serviceUrl)) {
+                applicationTypeComboBox.addItem(type);
+            }
+            versionTextField.setText(micronautVersion);
+            initialized = true;
+        } catch (Exception ex) {
+            panel.wizardDescriptor.putProperty(WizardDescriptor.PROP_ERROR_MESSAGE, "Could not query Micronaut Launch service");
+            failed = true;
+            panel.fireChangeEvent();
+        }
+    }
+
+    @Override
+    public void finished() {
+        if (initialized) {
+            panel.fireChangeEvent();
+            groupTextField.requestFocus();
+        }
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        versionTextField.setText("");
+        applicationTypeComboBox.removeAllItems();
+        if ("CUSTOM".equals(e.getActionCommand())) {
+            customTextField.requestFocus();
+        } else {
+            refresh();
+        }
+    }
+
+    private void refresh() {
+        initialized = false;
+        failed = false;
+        RequestProcessor.getDefault().post(() -> {
+            construct();
+            SwingUtilities.invokeLater(() -> {
+                finished();
+            });
+        });
+    }
+
+    private String getServiceUrl() {
+        switch (serviceButtonGroup.getSelection().getActionCommand()) {
+            case "DEFAULT":
+                return MicronautLaunchService.defaultURL;
+            case "SNAPSHOT":
+                return MicronautLaunchService.snapshotURL;
+            default:
+                return customTextField.getText();
+        }
+    }
+
+    private boolean customURLValid() {
+        try {
+            new URL(customTextField.getText());
+        } catch (MalformedURLException ex) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/BasePropertiesWizardPanel.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/BasePropertiesWizardPanel.java
new file mode 100644
index 0000000..3fc91d0
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/BasePropertiesWizardPanel.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.micronaut.newproject;
+
+import java.awt.Component;
+import javax.swing.event.ChangeListener;
+import org.openide.WizardDescriptor;
+import org.openide.WizardValidationException;
+import org.openide.util.ChangeSupport;
+import org.openide.util.HelpCtx;
+import org.openide.util.NbBundle;
+
+/**
+ * Wizard descriptor for Base Properties step in Micronaut project wizard.
+ *
+ * @author Dusan Balek
+ */
+public class BasePropertiesWizardPanel implements WizardDescriptor.ValidatingPanel<WizardDescriptor>, WizardDescriptor.FinishablePanel<WizardDescriptor> {
+
+    WizardDescriptor wizardDescriptor;
+    private BasePropertiesVisual component;
+
+    public BasePropertiesWizardPanel() {
+    }
+
+    @Override
+    @NbBundle.Messages("LBL_BasePropertiesStep=Base Properties")
+    public Component getComponent() {
+        if (component == null) {
+            component = new BasePropertiesVisual(this);
+            component.setName(Bundle.LBL_BasePropertiesStep());
+        }
+        return component;
+    }
+
+    @Override
+    public HelpCtx getHelp() {
+        // Show no Help button for this panel:
+        return HelpCtx.DEFAULT_HELP;
+        // If you have context help:
+        // return new HelpCtx("help.key.here");
+    }
+
+    @Override
+    public boolean isValid() {
+        getComponent();
+        return component.valid(wizardDescriptor);
+    }
+
+    private final ChangeSupport chgSupport = new ChangeSupport(this);
+
+    @Override
+    public final void addChangeListener(ChangeListener l) {
+        synchronized (chgSupport) {
+            chgSupport.addChangeListener(l);
+        }
+    }
+
+    @Override
+    public final void removeChangeListener(ChangeListener l) {
+        synchronized (chgSupport) {
+            chgSupport.removeChangeListener(l);
+        }
+    }
+
+    protected final void fireChangeEvent() {
+        chgSupport.fireChange();
+    }
+
+    @Override
+    public void readSettings(WizardDescriptor wiz) {
+        wizardDescriptor = wiz;
+        component.read(wizardDescriptor);
+    }
+
+    @Override
+    public void storeSettings(WizardDescriptor wiz) {
+        WizardDescriptor d = wiz;
+        component.store(d);
+    }
+
+    @Override
+    public boolean isFinishPanel() {
+        return true;
+    }
+
+    @Override
+    public void validate() throws WizardValidationException {
+        getComponent();
+        component.validate(wizardDescriptor);
+    }
+}
diff --git a/java/java.sourceui/nbproject/project.properties b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/Bundle.properties
similarity index 63%
copy from java/java.sourceui/nbproject/project.properties
copy to enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/Bundle.properties
index 01b9ec4..24c11d1 100644
--- a/java/java.sourceui/nbproject/project.properties
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/Bundle.properties
@@ -14,14 +14,21 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-javadoc.apichanges=${basedir}/apichanges.xml
-javac.compilerargs=-Xlint -Xlint:-serial
-javac.source=1.8
-javadoc.arch=${basedir}/arch.xml
-spec.version.base=1.57.0
 
-test.config.stableBTD.includes=**/*Test.class
-test.config.stableBTD.excludes=\
-    **/ElementHeadersTest.class
-
-requires.nb.javac=true
+LBL_ProjectName=Project &Name\:
+LBL_ProjectLocation=Project &Location\:
+LBL_ProjectFolder=Project Fol&der:
+BTN_Browse=Br&owse...
+LBL_ChooseServiceURL=Choose service URL:
+LBL_Default=Default:
+LBL_Snapshot=Snapshot:
+LBL_Custom=Custom:
+LBL_Group=Group:
+LBL_Artifact=Artifact:
+LBL_Version=Micronaut version:
+LBL_ApplicationType=Application type:
+LBL_JavaVersion=Java version:
+LBL_Language=Language:
+LBL_Java=Java
+LBL_Kotlin=Kotlin
+LBL_Groovy=Groovy
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/FeatureTogglePanel.form b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/FeatureTogglePanel.form
new file mode 100644
index 0000000..3a4d379
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/FeatureTogglePanel.form
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+
+<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Component id="featureCheckBox" min="-2" max="-2" attributes="0"/>
+          <Group type="102" attributes="0">
+              <EmptySpace min="21" pref="21" max="-2" attributes="0"/>
+              <Component id="descriptionLabel" min="-2" max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <Component id="featureCheckBox" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="descriptionLabel" min="-2" max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Component class="javax.swing.JCheckBox" name="featureCheckBox">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+          <Connection code="feature.getTitle()" type="code"/>
+        </Property>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JLabel" name="descriptionLabel">
+      <Properties>
+        <Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
+          <FontInfo relative="true">
+            <Font bold="false" component="descriptionLabel" property="font" relativeSize="true" size="-1"/>
+          </FontInfo>
+        </Property>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+          <Connection code="feature.getDescription()" type="code"/>
+        </Property>
+      </Properties>
+    </Component>
+  </SubComponents>
+</Form>
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/FeatureTogglePanel.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/FeatureTogglePanel.java
new file mode 100644
index 0000000..f8119af
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/FeatureTogglePanel.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.micronaut.newproject;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+public class FeatureTogglePanel extends javax.swing.JPanel {
+
+    private final MicronautLaunchService.Feature feature;
+
+    /**
+     * Creates new form FeatureTogglePanel
+     */
+    public FeatureTogglePanel(MicronautLaunchService.Feature feature) {
+        this.feature = feature;
+        initComponents();
+    }
+
+    public MicronautLaunchService.Feature getFeature() {
+        return feature;
+    }
+
+    public boolean isSelected() {
+        return featureCheckBox.isSelected();
+    }
+
+    public void setSelected(boolean b) {
+        featureCheckBox.setSelected(b);
+    }
+
+    /**
+     * This method is called from within the constructor to initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is always
+     * regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        featureCheckBox = new javax.swing.JCheckBox();
+        descriptionLabel = new javax.swing.JLabel();
+
+        org.openide.awt.Mnemonics.setLocalizedText(featureCheckBox, feature.getTitle());
+
+        descriptionLabel.setFont(descriptionLabel.getFont().deriveFont(descriptionLabel.getFont().getStyle() & ~java.awt.Font.BOLD, descriptionLabel.getFont().getSize()-1));
+        org.openide.awt.Mnemonics.setLocalizedText(descriptionLabel, feature.getDescription());
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+        this.setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(featureCheckBox)
+            .addGroup(layout.createSequentialGroup()
+                .addGap(21, 21, 21)
+                .addComponent(descriptionLabel))
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addComponent(featureCheckBox)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(descriptionLabel))
+        );
+    }// </editor-fold>//GEN-END:initComponents
+
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JLabel descriptionLabel;
+    private javax.swing.JCheckBox featureCheckBox;
+    // End of variables declaration//GEN-END:variables
+}
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/FeaturesVisual.form b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/FeaturesVisual.form
new file mode 100644
index 0000000..195a3d4
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/FeaturesVisual.form
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+
+<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Component id="scrollPane" alignment="0" pref="556" max="32767" attributes="0"/>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Component id="scrollPane" alignment="0" pref="298" max="32767" attributes="0"/>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JScrollPane" name="scrollPane">
+      <Properties>
+        <Property name="horizontalScrollBarPolicy" type="int" value="31"/>
+      </Properties>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+      <SubComponents>
+        <Container class="javax.swing.JPanel" name="nestedPanel">
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
+        </Container>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/FeaturesVisual.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/FeaturesVisual.java
new file mode 100644
index 0000000..39736bf
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/FeaturesVisual.java
@@ -0,0 +1,190 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.micronaut.newproject;
+
+import java.awt.Insets;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+
+import org.openide.WizardDescriptor;
+import org.openide.WizardValidationException;
+import org.openide.util.AsyncGUIJob;
+import org.openide.util.RequestProcessor;
+
+/**
+ * Options panel for Features step in Micronaut project wizard.
+ *
+ * @author Dusan Balek
+ */
+public class FeaturesVisual extends JPanel implements AsyncGUIJob {
+
+    private final FeaturesWizardPanel panel;
+    private boolean initialized = false;
+    private boolean failed = false;
+    private Map<String, List<FeatureTogglePanel>> featuresMap;
+
+    public FeaturesVisual(FeaturesWizardPanel panel) {
+        this.panel = panel;
+        initComponents();
+    }
+
+    @Override
+    public void addNotify() {
+        super.addNotify();
+        nestedPanel.requestFocus();
+    }
+
+    /** This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of
+     * this method is always regenerated by the Form Editor.
+     */
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+        java.awt.GridBagConstraints gridBagConstraints;
+
+        scrollPane = new javax.swing.JScrollPane();
+        nestedPanel = new javax.swing.JPanel();
+
+        scrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
+
+        nestedPanel.setLayout(new java.awt.GridBagLayout());
+        scrollPane.setViewportView(nestedPanel);
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+        this.setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(scrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 556, Short.MAX_VALUE)
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(scrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 298, Short.MAX_VALUE)
+        );
+    }// </editor-fold>//GEN-END:initComponents
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JPanel nestedPanel;
+    private javax.swing.JScrollPane scrollPane;
+    // End of variables declaration//GEN-END:variables
+
+    boolean valid(WizardDescriptor wizardDescriptor) {
+        if (failed) {
+            wizardDescriptor.putProperty(WizardDescriptor.PROP_ERROR_MESSAGE, "Problems in contacting service!");
+            return false;
+        }
+        wizardDescriptor.putProperty(WizardDescriptor.PROP_ERROR_MESSAGE, "");
+        return initialized;
+    }
+
+    void store(WizardDescriptor wd) {
+        Set<MicronautLaunchService.Feature> selectedFeatures = new LinkedHashSet<>();
+        for (List<FeatureTogglePanel> toggles : featuresMap.values()) {
+            for (FeatureTogglePanel toggle : toggles) {
+                if (toggle.isSelected()) {
+                    selectedFeatures.add(toggle.getFeature());
+                }
+            }
+        }
+        wd.putProperty(MicronautProjectWizardIterator.FEATURES, selectedFeatures);
+    }
+
+    void read(WizardDescriptor wd) {
+        Set<MicronautLaunchService.Feature> selectedFeatures = (Set<MicronautLaunchService.Feature>) wd.getProperty(MicronautProjectWizardIterator.FEATURES);
+        if (selectedFeatures != null && !selectedFeatures.isEmpty()) {
+            for (List<FeatureTogglePanel> toggles : featuresMap.values()) {
+                for (FeatureTogglePanel toggle : toggles) {
+                    toggle.setSelected(selectedFeatures.contains(toggle.getFeature()));
+                }
+            }
+        }
+    }
+
+    void validate(WizardDescriptor d) throws WizardValidationException {
+        // nothing to validate
+    }
+
+    @Override
+    public void construct() {
+        init();
+        panel.wizardDescriptor.addPropertyChangeListener((evt) -> {
+            if (evt.getPropertyName() == MicronautProjectWizardIterator.SERVICE_URL ||
+                    evt.getPropertyName() == MicronautProjectWizardIterator.APPLICATION_TYPE) {
+                refresh();
+            }
+        });
+    }
+
+    private void init() {
+        try {
+            featuresMap = new LinkedHashMap<>();
+            panel.wizardDescriptor.putProperty(WizardDescriptor.PROP_INFO_MESSAGE, "Contacting service...");
+            String serviceUrl = (String) panel.wizardDescriptor.getProperty(MicronautProjectWizardIterator.SERVICE_URL);
+            MicronautLaunchService.ApplicationType appType = (MicronautLaunchService.ApplicationType) panel.wizardDescriptor.getProperty(MicronautProjectWizardIterator.APPLICATION_TYPE);
+            for (MicronautLaunchService.Feature feature : MicronautLaunchService.getInstance().getFeatures(serviceUrl, appType)) {
+                List<FeatureTogglePanel> toggles = featuresMap.computeIfAbsent(feature.getCategory(), (c) -> new ArrayList<>());
+                toggles.add(new FeatureTogglePanel(feature));
+            }
+            java.awt.GridBagConstraints gridBagConstraints = new java.awt.GridBagConstraints();
+            gridBagConstraints.gridx = 0;
+            gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
+            gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
+            gridBagConstraints.weightx = 1.0;
+            gridBagConstraints.insets = new Insets(4, 8, 0, 0);
+            int i = 0;
+            for (Map.Entry<String, List<FeatureTogglePanel>> entry : featuresMap.entrySet()) {
+                gridBagConstraints.gridy = i++;
+                JLabel label = new JLabel(entry.getKey());
+                label.setFont(label.getFont().deriveFont(java.awt.Font.BOLD));
+                nestedPanel.add(label, gridBagConstraints);
+                for (FeatureTogglePanel toggle : entry.getValue()) {
+                    gridBagConstraints.gridy = i++;
+                    nestedPanel.add(toggle, gridBagConstraints);
+                }
+            }
+            nestedPanel.revalidate();
+            initialized = true;
+        } catch (Exception ex) {
+            panel.wizardDescriptor.putProperty(WizardDescriptor.PROP_ERROR_MESSAGE, "Could not query Micronaut Launch service");
+            failed = true;
+        }
+    }
+
+    @Override
+    public void finished() {
+        panel.fireChangeEvent();
+    }
+
+    private void refresh() {
+        initialized = false;
+        failed = false;
+        nestedPanel.removeAll();
+        RequestProcessor.getDefault().post(() -> {
+            init();
+            SwingUtilities.invokeLater(() -> {
+                finished();
+            });
+        });
+    }
+}
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/FeaturesWizardPanel.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/FeaturesWizardPanel.java
new file mode 100644
index 0000000..cea4597
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/FeaturesWizardPanel.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.micronaut.newproject;
+
+import java.awt.Component;
+import javax.swing.event.ChangeListener;
+
+import org.openide.WizardDescriptor;
+import org.openide.WizardValidationException;
+import org.openide.util.ChangeSupport;
+import org.openide.util.HelpCtx;
+import org.openide.util.NbBundle;
+
+/**
+ * Wizard descriptor for Features step in Micronaut project wizard.
+ *
+ * @author Dusan Balek
+ */
+public class FeaturesWizardPanel implements WizardDescriptor.ValidatingPanel<WizardDescriptor>, WizardDescriptor.FinishablePanel<WizardDescriptor> {
+
+    WizardDescriptor wizardDescriptor;
+    private FeaturesVisual component;
+
+    public FeaturesWizardPanel() {
+    }
+
+    @Override
+    @NbBundle.Messages("LBL_Features=Features")
+    public Component getComponent() {
+        if (component == null) {
+            component = new FeaturesVisual(this);
+            component.setName(Bundle.LBL_Features());
+        }
+        return component;
+    }
+
+    @Override
+    public HelpCtx getHelp() {
+        // Show no Help button for this panel:
+        return HelpCtx.DEFAULT_HELP;
+        // If you have context help:
+        // return new HelpCtx("help.key.here");
+    }
+
+    @Override
+    public boolean isValid() {
+        getComponent();
+        return component.valid(wizardDescriptor);
+    }
+
+    private final ChangeSupport chgSupport = new ChangeSupport(this);
+
+    @Override
+    public final void addChangeListener(ChangeListener l) {
+        synchronized (chgSupport) {
+            chgSupport.addChangeListener(l);
+        }
+    }
+
+    @Override
+    public final void removeChangeListener(ChangeListener l) {
+        synchronized (chgSupport) {
+            chgSupport.removeChangeListener(l);
+        }
+    }
+
+    protected final void fireChangeEvent() {
+        chgSupport.fireChange();
+    }
+
+    @Override
+    public void readSettings(WizardDescriptor wiz) {
+        wizardDescriptor = wiz;
+        component.read(wizardDescriptor);
+    }
+
+    @Override
+    public void storeSettings(WizardDescriptor wiz) {
+        WizardDescriptor d = wiz;
+        component.store(d);
+    }
+
+    @Override
+    public boolean isFinishPanel() {
+        return false;
+    }
+
+    @Override
+    public void validate() throws WizardValidationException {
+        getComponent();
+        component.validate(wizardDescriptor);
+    }
+}
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/MicronautGradleProjectDescription.html b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/MicronautGradleProjectDescription.html
new file mode 100644
index 0000000..7c2814e
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/MicronautGradleProjectDescription.html
@@ -0,0 +1,29 @@
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+    </head>
+    <body>
+        Gradle <b>Micronaut</b> project created trough the <i>Micronaut Launch</i> web service
+        (at <a href="https://micronaut.io/launch/">https://micronaut.io/launch/</a>)
+    </body>
+</html>
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/MicronautLaunchService.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/MicronautLaunchService.java
new file mode 100644
index 0000000..6b318ed
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/MicronautLaunchService.java
@@ -0,0 +1,174 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.micronaut.newproject;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Singleton class managing connection to the Micronaut Launch service.
+ *
+ * @author Dusan Balek
+ */
+public class MicronautLaunchService {
+
+    public static final String defaultURL = "https://launch.micronaut.io";
+    public static final String snapshotURL = "https://snapshot.micronaut.io";
+
+    private static final MicronautLaunchService INSTANCE = new MicronautLaunchService();
+    private static final String VERSIONS = "versions/";
+    private static final String APPLICATION_TYPES = "application-types/";
+    private static final String FEATURES = "features/";
+    private static final String CREATE = "create/";
+
+    private final Gson gson = new Gson();
+
+    private MicronautLaunchService() {
+    }
+
+    public static MicronautLaunchService getInstance() {
+        return INSTANCE;
+    }
+
+    public String getMicronautVersion(String serviceUrl) throws IOException {
+        if (!serviceUrl.endsWith("/")) {
+            serviceUrl = serviceUrl + '/';
+        }
+        JsonObject json = gson.fromJson(getJson(serviceUrl + VERSIONS), JsonObject.class);
+        return json.getAsJsonObject("versions").get("micronaut.version").getAsString();
+    }
+
+    public List<ApplicationType> getApplicationTypes(String serviceUrl) throws IOException {
+        if (!serviceUrl.endsWith("/")) {
+            serviceUrl = serviceUrl + '/';
+        }
+        JsonObject json = gson.fromJson(getJson(serviceUrl + APPLICATION_TYPES), JsonObject.class);
+        JsonArray jsonArray = json.getAsJsonArray("types");
+        ArrayList<ApplicationType> types = new ArrayList<>(jsonArray.size());
+        for (JsonElement jsonElement : jsonArray) {
+            JsonObject jsonObject = jsonElement.getAsJsonObject();
+            types.add(new ApplicationType(jsonObject.get("title").getAsString(), jsonObject.get("value").getAsString()));
+        }
+        return types;
+    }
+
+    public List<Feature> getFeatures(String serviceUrl, ApplicationType appType) throws IOException {
+        if (!serviceUrl.endsWith("/")) {
+            serviceUrl = serviceUrl + '/';
+        }
+        JsonObject json = gson.fromJson(getJson(serviceUrl + APPLICATION_TYPES + appType.value + '/' + FEATURES), JsonObject.class);
+        JsonArray jsonArray = json.getAsJsonArray("features");
+        ArrayList<Feature> features = new ArrayList<>(jsonArray.size());
+        for (JsonElement jsonElement : jsonArray) {
+            JsonObject jsonObject = jsonElement.getAsJsonObject();
+            features.add(new Feature(jsonObject.get("title").getAsString(), jsonObject.get("name").getAsString(),
+                    jsonObject.get("category").getAsString(), jsonObject.get("description").getAsString()));
+        }
+        return features;
+    }
+
+    public InputStream create(String serviceUrl, ApplicationType appType, String appName, String javaVersion, String language, String buildTool, Set<Feature> features) throws IOException {
+        StringBuilder sb = new StringBuilder(serviceUrl);
+        if (!serviceUrl.endsWith("/")) {
+            sb.append('/');
+        }
+        sb.append(CREATE).append(appType.value).append('/').append(appName);
+        sb.append("?javaVersion=JDK_").append(javaVersion);
+        sb.append("&lang=").append(language);
+        sb.append("&build=").append(buildTool);
+        sb.append("&test=JUNIT");
+        if (features != null) {
+            for (Feature feature : features) {
+                sb.append("&features=").append(feature.name);
+            }
+        }
+        return get(sb.toString());
+    }
+
+    private InputStream get(String serviceUrl) throws IOException {
+        URL url = new URL(serviceUrl);
+        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+        conn.setRequestMethod("GET");
+        return conn.getInputStream();
+    }
+
+    private String getJson(String serviceUrl) throws IOException {
+        StringBuilder result = new StringBuilder();
+        try (BufferedReader rd = new BufferedReader(new InputStreamReader(get(serviceUrl)))) {
+            String line;
+            while ((line = rd.readLine()) != null) {
+               result.append(line);
+            }
+        }
+        return result.toString();
+    }
+
+    public static class ApplicationType {
+
+        private String title;
+        private String value;
+
+        private ApplicationType(String name, String value) {
+            this.title = name;
+            this.value = value;
+        }
+
+        @Override
+        public String toString() {
+            return title;
+        }
+    }
+
+    public static class Feature {
+        private String title;
+        private String name;
+        private String category;
+        private String description;
+
+        private Feature(String title, String name, String category, String description) {
+            this.title = title;
+            this.name = name;
+            this.category = category;
+            this.description = description;
+        }
+
+        public String getTitle() {
+            return title;
+        }
+
+        public String getCategory() {
+            return category;
+        }
+
+        public String getDescription() {
+            return description;
+        }
+    }
+}
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/MicronautMavenProjectDescription.html b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/MicronautMavenProjectDescription.html
new file mode 100644
index 0000000..936484a
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/MicronautMavenProjectDescription.html
@@ -0,0 +1,29 @@
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+    </head>
+    <body>
+        Maven <b>Micronaut</b> project created trough the <i>Micronaut Launch</i> web service
+        (at <a href="https://micronaut.io/launch/">https://micronaut.io/launch/</a>)
+    </body>
+</html>
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/MicronautProjectWizardIterator.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/MicronautProjectWizardIterator.java
new file mode 100644
index 0000000..3072d1c
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/MicronautProjectWizardIterator.java
@@ -0,0 +1,224 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.micronaut.newproject;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Collections;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import javax.swing.JComponent;
+import javax.swing.event.ChangeListener;
+import org.netbeans.api.progress.ProgressHandle;
+import org.netbeans.api.project.Project;
+import org.netbeans.api.project.ProjectManager;
+import org.netbeans.api.templates.TemplateRegistration;
+import org.netbeans.spi.project.ActionProvider;
+import org.netbeans.spi.project.ui.support.ProjectChooser;
+import org.openide.WizardDescriptor;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.util.AsyncGUIJob;
+import org.openide.util.Exceptions;
+import org.openide.util.Lookup;
+import org.openide.util.NbBundle;
+import org.openide.util.Utilities;
+
+/**
+ * Wizard iterator for Micronaut projects.
+ *
+ * @author Dusan Balek
+ */
+@NbBundle.Messages("MicronautProject_DN=Micronaut Project")
+public class MicronautProjectWizardIterator implements WizardDescriptor.ProgressInstantiatingIterator<WizardDescriptor> {
+
+    @TemplateRegistration(folder = "Project/Maven2", position = 300, displayName = "#MicronautProject_DN", description = "MicronautMavenProjectDescription.html", iconBase = "org/netbeans/modules/micronaut/resources/micronaut.png")
+    public static class MavenMicronautProject extends MicronautProjectWizardIterator {
+
+        @Override
+        public void initialize(WizardDescriptor wizard) {
+            super.initialize(wizard);
+            wizard.putProperty(BUILD_TOOL, "MAVEN");
+        }
+    }
+
+    @TemplateRegistration(folder = "Project/Gradle", position = 300, displayName = "#MicronautProject_DN", description = "MicronautGradleProjectDescription.html", iconBase = "org/netbeans/modules/micronaut/resources/micronaut.png")
+    public static class GradleMicronautProject extends MicronautProjectWizardIterator {
+
+        @Override
+        public void initialize(WizardDescriptor wizard) {
+            super.initialize(wizard);
+            wizard.putProperty(BUILD_TOOL, "GRADLE");
+        }
+    }
+
+    public static final String PROJECT_NAME = "project.name";
+    public static final String PROJECT_LOCATION = "project.location";
+    public static final String SERVICE_URL = "service.url";
+    public static final String MAVEN_GROUP = "maven.group";
+    public static final String MAVEN_ARTIFACT = "maven.artifact";
+    public static final String APPLICATION_TYPE = "application.type";
+    public static final String JAVA_VERSION = "java.version";
+    public static final String LANGUAGE = "language";
+    public static final String BUILD_TOOL = "build.tool";
+    public static final String FEATURES = "features";
+
+    private transient int index;
+    private transient WizardDescriptor.Panel[] panels;
+    private transient WizardDescriptor wiz;
+
+    @Override
+    public Set instantiate(ProgressHandle handle) throws IOException {
+        try {
+            handle.start(4);
+            File projFile = FileUtil.normalizeFile((File) wiz.getProperty(PROJECT_LOCATION));
+            projFile.mkdirs();
+            handle.progress(1);
+            InputStream stream = MicronautLaunchService.getInstance().create((String) wiz.getProperty(SERVICE_URL),
+                    (MicronautLaunchService.ApplicationType) wiz.getProperty(APPLICATION_TYPE),
+                    (String) wiz.getProperty(MAVEN_GROUP) + '.' + (String) wiz.getProperty(MAVEN_ARTIFACT),
+                    (String) wiz.getProperty(JAVA_VERSION),
+                    (String) wiz.getProperty(LANGUAGE),
+                    (String) wiz.getProperty(BUILD_TOOL),
+                    (Set<MicronautLaunchService.Feature>) wiz.getProperty(FEATURES));
+            handle.progress(2);
+            FileObject projDir = FileUtil.toFileObject(projFile);
+            unzip(stream, projDir);
+            handle.progress(3);
+            ProjectManager.getDefault().clearNonProjectCache();
+            Project prj = ProjectManager.getDefault().findProject(projDir);
+            if (prj != null) {
+                ActionProvider actionProvider = prj.getLookup().lookup(ActionProvider.class);
+                if (actionProvider != null && actionProvider.isActionEnabled(ActionProvider.COMMAND_PRIME, Lookup.EMPTY)) {
+                    actionProvider.invokeAction(ActionProvider.COMMAND_PRIME, Lookup.EMPTY);
+                }
+            }
+            File parent = projFile.getParentFile();
+            if (parent != null && parent.exists()) {
+                ProjectChooser.setProjectsFolder(parent);
+            }
+            return Collections.singleton(projDir);
+        } catch (Exception ex) {
+            Exceptions.printStackTrace(ex);
+        } finally {
+            handle.finish();
+        }
+        return Collections.emptySet();
+    }
+
+    @Override
+    public Set instantiate() throws IOException {
+        throw new UnsupportedOperationException("Not supported.");
+    }
+
+    @Override
+    @NbBundle.Messages("LBL_WizardTitle=Micronaut Maven Project")
+    public void initialize(WizardDescriptor wizard) {
+        this.wiz = wizard;
+        wiz.putProperty("NewProjectWizard_Title", Bundle.LBL_WizardTitle()); //NOI18N
+        index = 0;
+        panels = new WizardDescriptor.Panel[] {
+            new NameAndLocationWizardPanel(),
+            new BasePropertiesWizardPanel(),
+            new FeaturesWizardPanel()
+        };
+        String[] steps = new String[] {
+            Bundle.LBL_NameAndLocationStep(),
+            Bundle.LBL_BasePropertiesStep(),
+            Bundle.LBL_Features()
+        };
+        for (int i = 0; i < panels.length; i++) {
+            JComponent jc = (JComponent) panels[i].getComponent();
+            jc.putClientProperty(WizardDescriptor.PROP_CONTENT_SELECTED_INDEX, i);
+            jc.putClientProperty(WizardDescriptor.PROP_CONTENT_DATA, steps);
+        }
+        Utilities.attachInitJob(panels[1].getComponent(), (AsyncGUIJob) panels[1].getComponent());
+        Utilities.attachInitJob(panels[2].getComponent(), (AsyncGUIJob) panels[2].getComponent());
+    }
+
+    @Override
+    public void uninitialize(WizardDescriptor wizard) {
+    }
+
+    @Override
+    public WizardDescriptor.Panel<WizardDescriptor> current() {
+        return panels[index];
+    }
+
+    @Override
+    @NbBundle.Messages({"# {0} - index", "# {1} - length", "NameFormat={0} of {1}"})
+    public String name() {
+        return Bundle.NameFormat(index + 1, panels.length);
+    }
+
+    @Override
+    public boolean hasNext() {
+        return index < panels.length - 1;
+    }
+
+    @Override
+    public boolean hasPrevious() {
+        return index > 0;
+    }
+
+    @Override
+    public void nextPanel() {
+        if (!hasNext()) {
+            throw new NoSuchElementException();
+        }
+        index++;
+    }
+
+    @Override
+    public void previousPanel() {
+        if (!hasPrevious()) {
+            throw new NoSuchElementException();
+        }
+        index--;
+    }
+
+    @Override
+    public void addChangeListener(ChangeListener l) {
+    }
+
+    @Override
+    public void removeChangeListener(ChangeListener l) {
+    }
+
+    private static void unzip(InputStream stream, FileObject folder) throws IOException {
+        try (ZipInputStream zis = new ZipInputStream(stream)) {
+            ZipEntry zipEntry;
+            while ((zipEntry = zis.getNextEntry()) != null) {
+                String entryName = zipEntry.getName();
+                if (zipEntry.isDirectory()) {
+                    FileUtil.createFolder(folder, entryName);
+                } else {
+                    FileObject fo = FileUtil.createData(folder, entryName);
+                    try (OutputStream out = fo.getOutputStream()) {
+                        FileUtil.copy(zis, out);
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/NameAndLocationVisual.form b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/NameAndLocationVisual.form
new file mode 100644
index 0000000..adc9781
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/NameAndLocationVisual.form
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+
+<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Component id="projectNameLabel" alignment="0" min="-2" max="-2" attributes="0"/>
+                  <Component id="projectLocationLabel" alignment="0" min="-2" max="-2" attributes="0"/>
+                  <Component id="createdFolderLabel" alignment="0" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace min="-2" max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Component id="projectNameTextField" alignment="1" max="32767" attributes="0"/>
+                  <Component id="projectLocationTextField" alignment="1" max="32767" attributes="0"/>
+                  <Component id="createdFolderTextField" alignment="1" max="32767" attributes="0"/>
+              </Group>
+              <EmptySpace min="-2" max="-2" attributes="0"/>
+              <Component id="browseButton" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" attributes="0">
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="projectNameLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="projectNameTextField" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="projectLocationLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="projectLocationTextField" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="browseButton" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="createdFolderLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="createdFolderTextField" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+              <EmptySpace max="32767" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Component class="javax.swing.JLabel" name="projectNameLabel">
+      <Properties>
+        <Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
+          <ComponentRef name="projectNameTextField"/>
+        </Property>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/netbeans/modules/micronaut/newproject/Bundle.properties" key="LBL_ProjectName" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+      <AuxValues>
+        <AuxValue name="generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
+      </AuxValues>
+    </Component>
+    <Component class="javax.swing.JTextField" name="projectNameTextField">
+    </Component>
+    <Component class="javax.swing.JLabel" name="projectLocationLabel">
+      <Properties>
+        <Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
+          <ComponentRef name="projectLocationTextField"/>
+        </Property>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/netbeans/modules/micronaut/newproject/Bundle.properties" key="LBL_ProjectLocation" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+      <AuxValues>
+        <AuxValue name="generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
+      </AuxValues>
+    </Component>
+    <Component class="javax.swing.JTextField" name="projectLocationTextField">
+    </Component>
+    <Component class="javax.swing.JButton" name="browseButton">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/netbeans/modules/micronaut/newproject/Bundle.properties" key="BTN_Browse" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+        <Property name="actionCommand" type="java.lang.String" value="BROWSE"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="browseButtonActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JLabel" name="createdFolderLabel">
+      <Properties>
+        <Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
+          <ComponentRef name="createdFolderTextField"/>
+        </Property>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="org/netbeans/modules/micronaut/newproject/Bundle.properties" key="LBL_ProjectFolder" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+    </Component>
+    <Component class="javax.swing.JTextField" name="createdFolderTextField">
+      <Properties>
+        <Property name="editable" type="boolean" value="false"/>
+      </Properties>
+    </Component>
+  </SubComponents>
+</Form>
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/NameAndLocationVisual.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/NameAndLocationVisual.java
new file mode 100644
index 0000000..dc4d217
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/NameAndLocationVisual.java
@@ -0,0 +1,273 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.micronaut.newproject;
+
+import java.io.File;
+import javax.swing.JFileChooser;
+import javax.swing.JPanel;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.text.Document;
+import org.netbeans.spi.project.ui.support.ProjectChooser;
+import org.openide.WizardDescriptor;
+import org.openide.WizardValidationException;
+import org.openide.filesystems.FileUtil;
+import org.openide.util.NbBundle;
+
+/**
+ * Options panel for the Name and Location step in Micronaut project wizard.
+ *
+ * @author Dusan Balek
+ */
+public class NameAndLocationVisual extends JPanel implements DocumentListener {
+
+    public static final String PROP_PROJECT_NAME = "projectName";
+
+    private final NameAndLocationWizardPanel panel;
+
+    public NameAndLocationVisual(NameAndLocationWizardPanel panel) {
+        initComponents();
+        this.panel = panel;
+        // Register listener on the textFields to make the automatic updates
+        projectNameTextField.getDocument().addDocumentListener(this);
+        projectLocationTextField.getDocument().addDocumentListener(this);
+    }
+
+    /** This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of
+     * this method is always regenerated by the Form Editor.
+     */
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        projectNameLabel = new javax.swing.JLabel();
+        projectNameTextField = new javax.swing.JTextField();
+        projectLocationLabel = new javax.swing.JLabel();
+        projectLocationTextField = new javax.swing.JTextField();
+        browseButton = new javax.swing.JButton();
+        createdFolderLabel = new javax.swing.JLabel();
+        createdFolderTextField = new javax.swing.JTextField();
+
+        projectNameLabel.setLabelFor(projectNameTextField);
+        org.openide.awt.Mnemonics.setLocalizedText(projectNameLabel, org.openide.util.NbBundle.getMessage(NameAndLocationVisual.class, "LBL_ProjectName")); // NOI18N
+
+        projectLocationLabel.setLabelFor(projectLocationTextField);
+        org.openide.awt.Mnemonics.setLocalizedText(projectLocationLabel, org.openide.util.NbBundle.getMessage(NameAndLocationVisual.class, "LBL_ProjectLocation")); // NOI18N
+
+        org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(NameAndLocationVisual.class, "BTN_Browse")); // NOI18N
+        browseButton.setActionCommand("BROWSE");
+        browseButton.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                browseButtonActionPerformed(evt);
+            }
+        });
+
+        createdFolderLabel.setLabelFor(createdFolderTextField);
+        org.openide.awt.Mnemonics.setLocalizedText(createdFolderLabel, org.openide.util.NbBundle.getMessage(NameAndLocationVisual.class, "LBL_ProjectFolder")); // NOI18N
+
+        createdFolderTextField.setEditable(false);
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+        this.setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(projectNameLabel)
+                    .addComponent(projectLocationLabel)
+                    .addComponent(createdFolderLabel))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(projectNameTextField, javax.swing.GroupLayout.Alignment.TRAILING)
+                    .addComponent(projectLocationTextField, javax.swing.GroupLayout.Alignment.TRAILING)
+                    .addComponent(createdFolderTextField, javax.swing.GroupLayout.Alignment.TRAILING))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(browseButton)
+                .addContainerGap())
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(projectNameLabel)
+                    .addComponent(projectNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(projectLocationLabel)
+                    .addComponent(projectLocationTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(browseButton))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(createdFolderLabel)
+                    .addComponent(createdFolderTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+    }// </editor-fold>//GEN-END:initComponents
+
+    @NbBundle.Messages("TIT_Select_Project_Location=Select Project Location")
+    private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed
+        String command = evt.getActionCommand();
+        if ("BROWSE".equals(command)) {
+            JFileChooser chooser = new JFileChooser();
+            chooser.setDialogTitle(Bundle.TIT_Select_Project_Location());
+            chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+            String path = this.projectLocationTextField.getText();
+            if (path.length() > 0) {
+                File f = new File(path);
+                if (f.exists()) {
+                    chooser.setSelectedFile(f);
+                }
+            }
+            if (JFileChooser.APPROVE_OPTION == chooser.showOpenDialog(this)) {
+                File projectDir = chooser.getSelectedFile();
+                projectLocationTextField.setText(FileUtil.normalizeFile(projectDir).getAbsolutePath());
+            }
+            panel.fireChangeEvent();
+        }
+    }//GEN-LAST:event_browseButtonActionPerformed
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton browseButton;
+    private javax.swing.JLabel createdFolderLabel;
+    private javax.swing.JTextField createdFolderTextField;
+    private javax.swing.JLabel projectLocationLabel;
+    private javax.swing.JTextField projectLocationTextField;
+    private javax.swing.JLabel projectNameLabel;
+    private javax.swing.JTextField projectNameTextField;
+    // End of variables declaration//GEN-END:variables
+
+    @Override
+    public void addNotify() {
+        super.addNotify();
+        //same problem as in 31086, initial focus on Cancel button
+        projectNameTextField.requestFocus();
+    }
+
+    boolean valid(WizardDescriptor wizardDescriptor) {
+        if (projectNameTextField.getText().length() == 0) {
+            wizardDescriptor.putProperty(WizardDescriptor.PROP_ERROR_MESSAGE, "Project Name is not a valid folder name.");
+            return false;
+        }
+        File f = FileUtil.normalizeFile(new File(projectLocationTextField.getText()).getAbsoluteFile());
+        if (!f.isDirectory()) {
+            wizardDescriptor.putProperty("WizardPanel_errorMessage", "Project Folder is not a valid path.");
+            return false;
+        }
+        final File destFolder = FileUtil.normalizeFile(new File(createdFolderTextField.getText()).getAbsoluteFile());
+        File projLoc = destFolder;
+        while (projLoc != null && !projLoc.exists()) {
+            projLoc = projLoc.getParentFile();
+        }
+        if (projLoc == null || !projLoc.canWrite()) {
+            wizardDescriptor.putProperty(WizardDescriptor.PROP_ERROR_MESSAGE, "Project Folder cannot be created.");
+            return false;
+        }
+        if (FileUtil.toFileObject(projLoc) == null) {
+            wizardDescriptor.putProperty(WizardDescriptor.PROP_ERROR_MESSAGE, "Project Folder is not a valid path.");
+            return false;
+        }
+        File[] kids = destFolder.listFiles();
+        if (destFolder.exists() && kids != null && kids.length > 0) {
+            wizardDescriptor.putProperty(WizardDescriptor.PROP_ERROR_MESSAGE, "Project Folder already exists and is not empty.");
+            return false;
+        }
+        wizardDescriptor.putProperty(WizardDescriptor.PROP_ERROR_MESSAGE, "");
+        return true;
+    }
+
+    void store(WizardDescriptor d) {
+        String name = projectNameTextField.getText().trim();
+        String folder = createdFolderTextField.getText().trim();
+        d.putProperty(MicronautProjectWizardIterator.PROJECT_NAME, name);
+        d.putProperty(MicronautProjectWizardIterator.PROJECT_LOCATION, new File(folder));
+        d.putProperty(MicronautProjectWizardIterator.MAVEN_ARTIFACT, toJavaName(name));
+    }
+
+    void read(WizardDescriptor settings) {
+        File projectLocation = (File) settings.getProperty(MicronautProjectWizardIterator.PROJECT_LOCATION);
+        if (projectLocation == null || projectLocation.getParentFile() == null || !projectLocation.getParentFile().isDirectory()) {
+            projectLocation = ProjectChooser.getProjectsFolder();
+        } else {
+            projectLocation = projectLocation.getParentFile();
+        }
+        this.projectLocationTextField.setText(projectLocation.getAbsolutePath());
+        String projectName = (String) settings.getProperty(MicronautProjectWizardIterator.PROJECT_NAME);
+        if (projectName == null) {
+            projectName = "MicronautProject";
+        }
+        this.projectNameTextField.setText(projectName);
+        this.projectNameTextField.selectAll();
+    }
+
+    void validate(WizardDescriptor d) throws WizardValidationException {
+        // nothing to validate
+    }
+
+    // Implementation of DocumentListener --------------------------------------
+    @Override
+    public void changedUpdate(DocumentEvent e) {
+        updateTexts(e);
+        if (this.projectNameTextField.getDocument() == e.getDocument()) {
+            firePropertyChange(PROP_PROJECT_NAME, null, this.projectNameTextField.getText());
+        }
+    }
+
+    @Override
+    public void insertUpdate(DocumentEvent e) {
+        updateTexts(e);
+        if (this.projectNameTextField.getDocument() == e.getDocument()) {
+            firePropertyChange(PROP_PROJECT_NAME, null, this.projectNameTextField.getText());
+        }
+    }
+
+    @Override
+    public void removeUpdate(DocumentEvent e) {
+        updateTexts(e);
+        if (this.projectNameTextField.getDocument() == e.getDocument()) {
+            firePropertyChange(PROP_PROJECT_NAME, null, this.projectNameTextField.getText());
+        }
+    }
+
+    /** Handles changes in the Project name and project directory, */
+    private void updateTexts(DocumentEvent e) {
+        Document doc = e.getDocument();
+        if (doc == projectNameTextField.getDocument() || doc == projectLocationTextField.getDocument()) {
+            // Change in the project name
+            String projectName = projectNameTextField.getText();
+            String projectFolder = projectLocationTextField.getText();
+            createdFolderTextField.setText(projectFolder + File.separatorChar + projectName);
+        }
+        // Notify that the panel changed
+        panel.fireChangeEvent();
+    }
+
+    private static String toJavaName(String name) {
+        StringBuilder javaName = new StringBuilder(name);
+        if (!Character.isJavaIdentifierStart(javaName.charAt(0))) {
+            javaName.setCharAt(0, '_');
+        }
+        for (int i = 1; i < name.length(); i++) {
+            if (!Character.isJavaIdentifierPart(javaName.charAt(i))) {
+                javaName.setCharAt(i, '_');
+            }
+        }
+        return javaName.toString();
+    }
+}
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/NameAndLocationWizardPanel.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/NameAndLocationWizardPanel.java
new file mode 100644
index 0000000..4760ee6
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/newproject/NameAndLocationWizardPanel.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.micronaut.newproject;
+
+import java.awt.Component;
+import javax.swing.event.ChangeListener;
+import org.openide.WizardDescriptor;
+import org.openide.WizardValidationException;
+import org.openide.util.ChangeSupport;
+import org.openide.util.HelpCtx;
+import org.openide.util.NbBundle;
+
+/**
+ * Wizard descriptor for Name and Location step in Micronaut project wizard.
+ *
+ * @author Dusan Balek
+ */
+public class NameAndLocationWizardPanel implements WizardDescriptor.ValidatingPanel<WizardDescriptor>, WizardDescriptor.FinishablePanel<WizardDescriptor> {
+
+    private WizardDescriptor wizardDescriptor;
+    private NameAndLocationVisual component;
+
+    public NameAndLocationWizardPanel() {
+    }
+
+    @Override
+    @NbBundle.Messages("LBL_NameAndLocationStep=Name and Location")
+    public Component getComponent() {
+        if (component == null) {
+            component = new NameAndLocationVisual(this);
+            component.setName(Bundle.LBL_NameAndLocationStep());
+        }
+        return component;
+    }
+
+    @Override
+    public HelpCtx getHelp() {
+        // Show no Help button for this panel:
+        return HelpCtx.DEFAULT_HELP;
+        // If you have context help:
+        // return new HelpCtx("help.key.here");
+    }
+
+    @Override
+    public boolean isValid() {
+        getComponent();
+        return component.valid(wizardDescriptor);
+    }
+
+    private final ChangeSupport chgSupport = new ChangeSupport(this);
+
+    @Override
+    public final void addChangeListener(ChangeListener l) {
+        synchronized (chgSupport) {
+            chgSupport.addChangeListener(l);
+        }
+    }
+
+    @Override
+    public final void removeChangeListener(ChangeListener l) {
+        synchronized (chgSupport) {
+            chgSupport.removeChangeListener(l);
+        }
+    }
+
+    protected final void fireChangeEvent() {
+        chgSupport.fireChange();
+    }
+
+    @Override
+    public void readSettings(WizardDescriptor wiz) {
+        wizardDescriptor = wiz;
+        component.read(wizardDescriptor);
+    }
+
+    @Override
+    public void storeSettings(WizardDescriptor wiz) {
+        WizardDescriptor d = wiz;
+        component.store(d);
+    }
+
+    @Override
+    public boolean isFinishPanel() {
+        return false;
+    }
+
+    @Override
+    public void validate() throws WizardValidationException {
+        getComponent();
+        component.validate(wizardDescriptor);
+    }
+}
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/refactor/MicronautRefactoringFactory.java b/enterprise/micronaut/src/org/netbeans/modules/micronaut/refactor/MicronautRefactoringFactory.java
new file mode 100644
index 0000000..f2e1ef5
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/refactor/MicronautRefactoringFactory.java
@@ -0,0 +1,243 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.micronaut.refactor;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+import javax.swing.text.Position;
+import org.netbeans.api.java.project.JavaProjectConstants;
+import org.netbeans.api.java.source.JavaSource;
+import org.netbeans.api.java.source.TreePathHandle;
+import org.netbeans.api.project.FileOwnerQuery;
+import org.netbeans.api.project.Project;
+import org.netbeans.api.project.ProjectUtils;
+import org.netbeans.api.project.SourceGroup;
+import org.netbeans.modules.micronaut.MicronautConfigProperties;
+import org.netbeans.modules.micronaut.MicronautConfigUtilities;
+import org.netbeans.modules.micronaut.completion.MicronautConfigCompletionItem;
+import org.netbeans.modules.refactoring.api.AbstractRefactoring;
+import org.netbeans.modules.refactoring.api.Problem;
+import org.netbeans.modules.refactoring.api.Scope;
+import org.netbeans.modules.refactoring.api.WhereUsedQuery;
+import org.netbeans.modules.refactoring.spi.RefactoringElementsBag;
+import org.netbeans.modules.refactoring.spi.RefactoringPlugin;
+import org.netbeans.modules.refactoring.spi.RefactoringPluginFactory;
+import org.netbeans.modules.refactoring.spi.SimpleRefactoringElementImplementation;
+import org.openide.cookies.EditorCookie;
+import org.openide.filesystems.FileObject;
+import org.openide.loaders.DataObject;
+import org.openide.loaders.DataObjectNotFoundException;
+import org.openide.text.CloneableEditorSupport;
+import org.openide.text.PositionBounds;
+import org.openide.util.Exceptions;
+import org.openide.util.Lookup;
+import org.openide.util.lookup.ServiceProvider;
+import org.springframework.boot.configurationmetadata.ConfigurationMetadataGroup;
+import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;
+import org.springframework.boot.configurationmetadata.ConfigurationMetadataSource;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+@ServiceProvider(service=org.netbeans.modules.refactoring.spi.RefactoringPluginFactory.class)
+public class MicronautRefactoringFactory implements RefactoringPluginFactory {
+
+    @Override
+    public RefactoringPlugin createInstance(AbstractRefactoring refactoring) {
+        Lookup lkp = refactoring.getRefactoringSource();
+        TreePathHandle handle = lkp.lookup(TreePathHandle.class);
+        if (refactoring instanceof WhereUsedQuery && ((WhereUsedQuery) refactoring).getBooleanValue(WhereUsedQuery.FIND_REFERENCES)) {
+            if (handle != null) {
+                return new MicronautWhereUsedRefactoringPlugin((WhereUsedQuery) refactoring);
+            }
+        }
+        return null;
+    }
+
+    private static class MicronautWhereUsedRefactoringPlugin implements RefactoringPlugin {
+
+        private final WhereUsedQuery refactoring;
+
+        public MicronautWhereUsedRefactoringPlugin(WhereUsedQuery refactoring) {
+            this.refactoring = refactoring;
+        }
+
+        @Override
+        public Problem preCheck() {
+            return null;
+        }
+
+        @Override
+        public Problem checkParameters() {
+            return null;
+        }
+
+        @Override
+        public Problem fastCheckParameters() {
+            return null;
+        }
+
+        @Override
+        public void cancelRequest() {
+        }
+
+        @Override
+        public Problem prepare(RefactoringElementsBag refactoringElements) {
+            Scope scope = refactoring.getContext().lookup(Scope.class);
+            if (scope != null) {
+                Set<Project> projects = new HashSet<>();
+                for (FileObject sourceRoot : scope.getSourceRoots()) {
+                    Project p = FileOwnerQuery.getOwner(sourceRoot);
+                    if (p != null) {
+                        projects.add(p);
+                    }
+                }
+                try {
+                    Info info = null;
+                    for (Project project : projects) {
+                        if (MicronautConfigProperties.hasConfigMetadata(project)) {
+                            SourceGroup[] sourceGroups = ProjectUtils.getSources(project).getSourceGroups(JavaProjectConstants.SOURCES_TYPE_RESOURCES);
+                            for (SourceGroup sourceGroup : sourceGroups) {
+                                FileObject rootFolder = sourceGroup.getRootFolder();
+                                FileObject fo = rootFolder.getFileObject("application.yml");
+                                if (fo != null) {
+                                    if (info == null) {
+                                        info = getInfo();
+                                    }
+                                    if (info.className != null && info.methodName != null && info.methodName.startsWith("set")) {
+                                        for (ConfigurationMetadataGroup group : MicronautConfigProperties.getGroups(project).values()) {
+                                            ConfigurationMetadataSource source = group.getSources().get(info.className);
+                                            if (source != null) {
+                                                for (ConfigurationMetadataProperty property : source.getProperties().values()) {
+                                                    String name = "set" + property.getName().replaceAll("-", "");
+                                                    if (name.equalsIgnoreCase(info.methodName)) {
+                                                        MicronautConfigUtilities.collectUsages(fo, property.getId(), usage -> {
+                                                            refactoringElements.add(refactoring, new WhereUsedRefactoringElement(usage.getFileObject(), usage.getStartOffset(), usage.getEndOffset(), usage.getText()));
+                                                        });
+                                                    }
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                } catch (IOException ioe) {
+                }
+            }
+            return null;
+        }
+
+        private Info getInfo() throws IOException {
+            final TreePathHandle handle = refactoring.getRefactoringSource().lookup(TreePathHandle.class);
+            final Info info = new Info();
+            JavaSource source = JavaSource.forFileObject(handle.getFileObject());
+            if (source != null) {
+                source.runUserActionTask(controller -> {
+                    controller.toPhase(JavaSource.Phase.RESOLVED);
+                    Element el = handle.resolveElement(controller);
+                    if (el != null && el.getKind() == ElementKind.METHOD && el.getModifiers().contains(Modifier.PUBLIC)) {
+                        info.methodName = el.getSimpleName().toString();
+                        info.className = ((TypeElement)((ExecutableElement)el).getEnclosingElement()).getQualifiedName().toString();
+                    }
+                }, true);
+            }
+            return info;
+        }
+
+        private static class Info {
+            private String className;
+            private String methodName;
+        }
+    }
+
+    public static final class WhereUsedRefactoringElement extends SimpleRefactoringElementImplementation {
+
+        private final FileObject fileObject;
+        private final int startOffset;
+        private final int endOffset;
+        private final String text;
+
+        private WhereUsedRefactoringElement(FileObject fileObject, int startOffset, int endOffset, String text) {
+            this.fileObject = fileObject;
+            this.startOffset = startOffset;
+            this.endOffset = endOffset;
+            this.text = text;
+        }
+
+        @Override
+        public String getText() {
+            return text;
+        }
+
+        @Override
+        public String getDisplayText() {
+            StringBuilder sb = new StringBuilder();
+            int idx = text.indexOf(':');
+            if (idx < 0) {
+                sb.append(text);
+            } else {
+                sb.append(MicronautConfigCompletionItem.PROPERTY_NAME_COLOR).append("<b>");
+                sb.append(text.substring(0, idx));
+                sb.append("</b></font>");
+                sb.append(text.substring(idx));
+            }
+            return sb.toString();
+        }
+
+        @Override
+        public void performChange() {
+        }
+
+        @Override
+        public Lookup getLookup() {
+            return Lookup.EMPTY;
+        }
+
+        @Override
+        public FileObject getParentFile() {
+            return fileObject;
+        }
+
+        @Override
+        public PositionBounds getPosition() {
+            try {
+                DataObject dobj = DataObject.find(getParentFile());
+                if (dobj != null) {
+                    EditorCookie.Observable obs = (EditorCookie.Observable)dobj.getCookie(EditorCookie.Observable.class);
+                    if (obs != null && obs instanceof CloneableEditorSupport) {
+                        CloneableEditorSupport supp = (CloneableEditorSupport)obs;
+                        return new PositionBounds(supp.createPositionRef(startOffset, Position.Bias.Forward), supp.createPositionRef(Math.max(startOffset, endOffset), Position.Bias.Forward));
+                    }
+                }
+            } catch (DataObjectNotFoundException ex) {
+                Exceptions.printStackTrace(ex);
+            }
+            return null;
+        }
+    }
+}
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/resources/layer.xml b/enterprise/micronaut/src/org/netbeans/modules/micronaut/resources/layer.xml
new file mode 100644
index 0000000..db3eff9
--- /dev/null
+++ b/enterprise/micronaut/src/org/netbeans/modules/micronaut/resources/layer.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.2//EN" "http://www.netbeans.org/dtds/filesystem-1_2.dtd">
+<filesystem>
+    <folder name="Editors">
+        <folder name="text">
+            <folder name="x-java">
+                <folder name="AnnotationProcessors">
+                    <file name="org-netbeans-modules-micronaut-completion-MicronautJavaConfigPropertiesCompletion.instance"/>
+                </folder>
+            </folder>
+        </folder>
+    </folder>
+</filesystem>
diff --git a/enterprise/micronaut/src/org/netbeans/modules/micronaut/resources/micronaut.png b/enterprise/micronaut/src/org/netbeans/modules/micronaut/resources/micronaut.png
new file mode 100644
index 0000000..d38f73f
Binary files /dev/null and b/enterprise/micronaut/src/org/netbeans/modules/micronaut/resources/micronaut.png differ
diff --git a/ide/api.lsp/build.xml b/ide/api.lsp/build.xml
new file mode 100644
index 0000000..9b6a11d
--- /dev/null
+++ b/ide/api.lsp/build.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<project basedir="." default="netbeans" name="ide/api.lsp">
+    <description>Builds, tests, and runs the project org.netbeans.api.lsp</description>
+    <import file="../../nbbuild/templates/projectized.xml"/>
+</project>
diff --git a/ide/api.lsp/manifest.mf b/ide/api.lsp/manifest.mf
new file mode 100644
index 0000000..2a6458d
--- /dev/null
+++ b/ide/api.lsp/manifest.mf
@@ -0,0 +1,6 @@
+Manifest-Version: 1.0
+OpenIDE-Module: org.netbeans.api.lsp/1
+OpenIDE-Module-Localizing-Bundle: org/netbeans/api/lsp/Bundle.properties
+OpenIDE-Module-Specification-Version: 1.0
+AutoUpdate-Show-In-Client: false
+
diff --git a/ide/libs.bytelist/external/binaries-list b/ide/api.lsp/nbproject/project.properties
similarity index 83%
copy from ide/libs.bytelist/external/binaries-list
copy to ide/api.lsp/nbproject/project.properties
index 0e0b70c1..0f73a11 100644
--- a/ide/libs.bytelist/external/binaries-list
+++ b/ide/api.lsp/nbproject/project.properties
@@ -14,5 +14,6 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-80294E59315B314D57782DC37F983AE5B29C2E4C org.jruby.extras:bytelist:1.0.15
-E2C76A19F00128BB1806207E2989139BFB45F49D org.jruby.jcodings:jcodings:1.0.18
+is.autoload=true
+javac.source=1.8
+javac.compilerargs=-Xlint -Xlint:-serial
diff --git a/ide/api.lsp/nbproject/project.xml b/ide/api.lsp/nbproject/project.xml
new file mode 100644
index 0000000..3d8cea7
--- /dev/null
+++ b/ide/api.lsp/nbproject/project.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<project xmlns="http://www.netbeans.org/ns/project/1">
+    <type>org.netbeans.modules.apisupport.project</type>
+    <configuration>
+        <data xmlns="http://www.netbeans.org/ns/nb-module-project/3">
+            <code-name-base>org.netbeans.api.lsp</code-name-base>
+            <module-dependencies>
+                <dependency>
+                    <code-name-base>org.netbeans.api.annotations.common</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <specification-version>1.39</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.netbeans.modules.editor.mimelookup</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <specification-version>1.52</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.netbeans.modules.editor.util</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <specification-version>1.77</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.filesystems</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>9.22</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.util</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>9.19</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.util.lookup</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>8.46</specification-version>
+                    </run-dependency>
+                </dependency>
+            </module-dependencies>
+            <test-dependencies>
+                <test-type>
+                    <name>unit</name>
+                    <test-dependency>
+                        <code-name-base>org.netbeans.libs.junit4</code-name-base>
+                        <compile-dependency/>
+                    </test-dependency>
+                    <test-dependency>
+                        <code-name-base>org.netbeans.modules.editor.mimelookup</code-name-base>
+                        <compile-dependency/>
+                        <test/>
+                    </test-dependency>
+                    <test-dependency>
+                        <code-name-base>org.netbeans.modules.nbjunit</code-name-base>
+                        <recursive/>
+                        <compile-dependency/>
+                    </test-dependency>
+                </test-type>
+            </test-dependencies>
+            <public-packages>
+                <package>org.netbeans.api.lsp</package>
+                <package>org.netbeans.spi.lsp</package>
+            </public-packages>
+        </data>
+    </configuration>
+</project>
diff --git a/ide/libs.bytelist/external/binaries-list b/ide/api.lsp/src/org/netbeans/api/lsp/Bundle.properties
similarity index 76%
copy from ide/libs.bytelist/external/binaries-list
copy to ide/api.lsp/src/org/netbeans/api/lsp/Bundle.properties
index 0e0b70c1..a610422 100644
--- a/ide/libs.bytelist/external/binaries-list
+++ b/ide/api.lsp/src/org/netbeans/api/lsp/Bundle.properties
@@ -14,5 +14,8 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-80294E59315B314D57782DC37F983AE5B29C2E4C org.jruby.extras:bytelist:1.0.15
-E2C76A19F00128BB1806207E2989139BFB45F49D org.jruby.jcodings:jcodings:1.0.18
+OpenIDE-Module-Display-Category=Base IDE
+OpenIDE-Module-Long-Description=\
+    Provides APIs and support classes for Language Server implementations.
+OpenIDE-Module-Name=LSP APIs
+OpenIDE-Module-Short-Description=Language Server Protocol APIs
diff --git a/ide/api.lsp/src/org/netbeans/api/lsp/Completion.java b/ide/api.lsp/src/org/netbeans/api/lsp/Completion.java
new file mode 100644
index 0000000..797714e
--- /dev/null
+++ b/ide/api.lsp/src/org/netbeans/api/lsp/Completion.java
@@ -0,0 +1,392 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.api.lsp;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+import javax.swing.text.Document;
+import org.netbeans.api.annotations.common.CheckForNull;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.api.annotations.common.NullAllowed;
+import org.netbeans.api.editor.mimelookup.MimeLookup;
+import org.netbeans.api.editor.mimelookup.MimePath;
+import org.netbeans.lib.editor.util.swing.DocumentUtilities;
+import org.netbeans.modules.lsp.CompletionAccessor;
+import org.netbeans.spi.lsp.CompletionCollector;
+
+/**
+ * Represents a completion proposal.
+ *
+ * @author Dusan Balek
+ * @since 1.0
+ */
+public final class Completion {
+
+    static {
+        CompletionAccessor.setDefault(new CompletionAccessor() {
+            @Override
+            public Completion createCompletion(String label, Kind kind, List<Tag> tags, CompletableFuture<String> detail, CompletableFuture<String> documentation,
+                    boolean preselect, String sortText, String filterText, String insertText, TextFormat insertTextFormat, TextEdit textEdit, CompletableFuture<List<TextEdit>> additionalTextEdits,
+                    List<Character> commitCharacters) {
+                return new Completion(label, kind, tags, detail, documentation, preselect, sortText, filterText, insertText, insertTextFormat, textEdit, additionalTextEdits, commitCharacters);
+            }
+        });
+    }
+
+    private final String label;
+    private final Kind kind;
+    private final List<Tag> tags;
+    private final CompletableFuture<String> detail;
+    private final CompletableFuture<String> documentation;
+    private final boolean preselect;
+    private final String sortText;
+    private final String filterText;
+    private final String insertText;
+    private final TextFormat insertTextFormat;
+    private final TextEdit textEdit;
+    private final CompletableFuture<List<TextEdit>> additionalTextEdits;
+    private final List<Character> commitCharacters;
+
+    private Completion(String label, Kind kind, List<Tag> tags, CompletableFuture<String> detail, CompletableFuture<String> documentation,
+            boolean preselect, String sortText, String filterText, String insertText, TextFormat insertTextFormat,
+            TextEdit textEdit, CompletableFuture<List<TextEdit>> additionalTextEdits, List<Character> commitCharacters) {
+        this.label = label;
+        this.kind = kind;
+        this.tags = tags;
+        this.detail = detail;
+        this.documentation = documentation;
+        this.preselect = preselect;
+        this.sortText = sortText;
+        this.filterText = filterText;
+        this.insertText = insertText;
+        this.insertTextFormat = insertTextFormat;
+        this.textEdit = textEdit;
+        this.additionalTextEdits = additionalTextEdits;
+        this.commitCharacters = commitCharacters;
+    }
+
+    /**
+     * The label of this completion. By default also the text that is inserted
+     * when selecting this completion.
+     *
+     * @since 1.0
+     */
+    @NonNull
+    public String getLabel() {
+        return label;
+    }
+
+    /**
+     * The kind of this completion.
+     *
+     * @since 1.0
+     */
+    @CheckForNull
+    public Kind getKind() {
+        return kind;
+    }
+
+    /**
+     * Tags for this completion.
+     *
+     * @since 1.0
+     */
+    @CheckForNull
+    public List<Tag> getTags() {
+        return tags != null ? Collections.unmodifiableList(tags) : null;
+    }
+
+    /**
+     * A human-readable string with additional information
+     * about this completion, like type or symbol information.
+     *
+     * @since 1.0
+     */
+    @CheckForNull
+    public CompletableFuture<String> getDetail() {
+        return detail;
+    }
+
+    /**
+     * A human-readable string that represents a doc-comment. An HTML format is
+     * supported.
+     *
+     * @since 1.0
+     */
+    @CheckForNull
+    public CompletableFuture<String> getDocumentation() {
+        return documentation;
+    }
+
+    /**
+     * Select this completion when showing.
+     *
+     * @since 1.0
+     */
+    public boolean isPreselect() {
+        return preselect;
+    }
+
+    /**
+     * A string that should be used when comparing this completion with other
+     * completions. When {@code null} the label is used as the sort text.
+     *
+     * @since 1.0
+     */
+    @CheckForNull
+    public String getSortText() {
+        return sortText;
+    }
+
+    /**
+     * A string that should be used when filtering a set of completions.
+     * When {@code null} the label is used as the filter.
+     *
+     * @since 1.0
+     */
+    @CheckForNull
+    public String getFilterText() {
+        return filterText;
+    }
+
+    /**
+     * A string that should be inserted into a document when selecting
+     * this completion. When {@code null} the label is used as the insert text.
+     *
+     * @since 1.0
+     */
+    @CheckForNull
+    public String getInsertText() {
+        return insertText;
+    }
+
+    /**
+     * The format of the insert text. The format applies to both the
+     * {@code insertText} property and the {@code newText} property of a provided
+     * {@code textEdit}. If omitted defaults to {@link TextFormat#PlainText}.
+     *
+     * @since 1.0
+     */
+    @CheckForNull
+    public TextFormat getInsertTextFormat() {
+        return insertTextFormat;
+    }
+
+    /**
+     * An edit which is applied to a document when selecting this completion.
+     * When an edit is provided the value of {@code insertText} is ignored.
+     * The range of the edit must be a single line range and it must
+     * contain the position at which completion has been requested.
+     *
+     * @since 1.0
+     */
+    @CheckForNull
+    public TextEdit getTextEdit() {
+        return textEdit;
+    }
+
+    /**
+     * A list of additional text edits that are applied when selecting this
+     * completion. Edits must not overlap (including the same insert position)
+     * with the main edit nor with themselves.
+     * Additional text edits should be used to change text unrelated to the
+     * current cursor position (for example adding an import statement at the
+     * top of the file if the completion item will insert an unqualified type).
+     *
+     * @since 1.0
+     */
+    @CheckForNull
+    public CompletableFuture<List<TextEdit>> getAdditionalTextEdits() {
+        return additionalTextEdits;
+    }
+
+    /**
+     * A list of characters that when pressed while this completion is
+     * active will accept it first and then type that character.
+     *
+     * @since 1.0
+     */
+    @CheckForNull
+    public List<Character> getCommitCharacters() {
+        return commitCharacters != null ? Collections.unmodifiableList(commitCharacters) : null;
+    }
+
+    /**
+     * Computes and collects completions for a document at a given offset. Example
+     * usage can be illustrated by:
+     * {@codesnippet CompletionTest#testCompletionCollect}
+     *
+     * @param doc a text document
+     * @param offset an offset inside the text document
+     * @param context an optional completion context
+     * @param consumer an operation accepting collected completions
+     *
+     * @return true if the list of collected completion is complete. If {@code false},
+     * further typing should result in subsequent calls to this method to recompute
+     * the completions.
+     *
+     * @since 1.0
+     */
+    public static boolean collect(@NonNull Document doc, int offset, @NullAllowed Context context, @NonNull Consumer<Completion> consumer) {
+        boolean isComplete = true;
+        MimePath mimePath = MimePath.parse(DocumentUtilities.getMimeType(doc));
+        for (CompletionCollector collector : MimeLookup.getLookup(mimePath).lookupAll(CompletionCollector.class)) {
+            isComplete &= collector.collectCompletions(doc, offset, context, consumer);
+        }
+        return isComplete;
+    }
+
+    /**
+     * Contains additional information about the context in which a request for
+     * collections completions is triggered.
+     *
+     * @since 1.0
+     */
+    public static final class Context {
+
+        private final TriggerKind triggerKind;
+        private final Character triggerCharacter;
+
+        public Context(@NonNull TriggerKind triggerKind, @NullAllowed Character triggerCharacter) {
+            this.triggerKind = triggerKind;
+            this.triggerCharacter = triggerCharacter;
+        }
+
+        /**
+         * How the completion was triggered.
+         *
+         * @since 1.0
+         */
+        @NonNull
+        public TriggerKind getTriggerKind() {
+            return triggerKind;
+        }
+
+        /**
+         * The trigger character that has trigger code complete.
+         * Is undefined if {@code triggerKind != TriggerKind.TriggerCharacter}.
+         *
+         * @since 1.0
+         */
+        @CheckForNull
+        public Character getTriggerCharacter() {
+            return triggerCharacter;
+        }
+    }
+
+    /**
+     * Specifies how a completion was triggered.
+     *
+     * @since 1.0
+     */
+    public enum TriggerKind {
+
+        /**
+         * Completion was triggered by typing an identifier (24x7 code
+         * complete), manual invocation (e.g Ctrl+Space) or via API.
+         *
+         * @since 1.0
+         */
+        Invoked,
+
+        /**
+         * Completion was triggered by a trigger character.
+         *
+         * @since 1.0
+         */
+        TriggerCharacter,
+
+        /**
+         * Completion was re-triggered as the current completion list is incomplete.
+         *
+         * @since 1.0
+         */
+        TriggerForIncompleteCompletions
+    }
+
+    /**
+     * The kind of a completion.
+     *
+     * @since 1.0
+     */
+    public static enum Kind {
+
+        Text,
+        Method,
+        Function,
+        Constructor,
+        Field,
+        Variable,
+        Class,
+        Interface,
+        Module,
+        Property,
+        Unit,
+        Value,
+        Enum,
+        Keyword,
+        Snippet,
+        Color,
+        File,
+        Reference,
+        Folder,
+        EnumMember,
+        Constant,
+        Struct,
+        Event,
+        Operator,
+        TypeParameter
+    }
+
+    /**
+     * Completion item tags are extra annotations that tweak the rendering of a
+     * completion.
+     *
+     * @since 1.0
+     */
+    public static enum Tag {
+
+        Deprecated
+    }
+
+    /**
+     * Defines whether the insert text in a completion item should be interpreted
+     * as plain text or a snippet.
+     *
+     * @since 1.0
+     */
+    public static enum TextFormat {
+
+        /**
+         * The primary text to be inserted is treated as a plain string.
+         *
+         * @since 1.0
+         */
+        PlainText,
+
+        /**
+         * The primary text to be inserted is treated as a snippet.
+         *
+         * @since 1.0
+         */
+        Snippet
+    }
+}
diff --git a/ide/api.lsp/src/org/netbeans/api/lsp/HyperlinkLocation.java b/ide/api.lsp/src/org/netbeans/api/lsp/HyperlinkLocation.java
new file mode 100644
index 0000000..1c449a5
--- /dev/null
+++ b/ide/api.lsp/src/org/netbeans/api/lsp/HyperlinkLocation.java
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.api.lsp;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+import javax.swing.text.Document;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.api.editor.mimelookup.MimeLookup;
+import org.netbeans.api.editor.mimelookup.MimePath;
+import org.netbeans.lib.editor.util.swing.DocumentUtilities;
+import org.netbeans.modules.lsp.HyperlinkLocationAccessor;
+import org.netbeans.spi.lsp.HyperlinkLocationProvider;
+import org.openide.filesystems.FileObject;
+
+/**
+ * Represents the target location of a hyperlink. Location is a range inside a
+ * file object, such as a line inside a text file.
+ *
+ * @author Dusan Balek
+ * @since 1.0
+ */
+public final class HyperlinkLocation {
+
+    static {
+        HyperlinkLocationAccessor.setDefault(new HyperlinkLocationAccessor() {
+            @Override
+            public HyperlinkLocation createHyperlinkLocation(FileObject fileObject, int startOffset, int endOffset) {
+                return new HyperlinkLocation(fileObject, startOffset, endOffset);
+            }
+        });
+    }
+
+    private final FileObject fileObject;
+    private final int startOffset;
+    private final int endOffset;
+
+    private HyperlinkLocation(@NonNull FileObject fileObject, int startOffset, int endOffset) {
+        this.fileObject = fileObject;
+        this.startOffset = startOffset;
+        this.endOffset = endOffset;
+    }
+
+    /**
+     * Target file object of this hyperlink.
+     *
+     * @return file object
+     *
+     * @since 1.0
+     */
+    @NonNull
+    public FileObject getFileObject() {
+        return fileObject;
+    }
+
+    /**
+     * The start offset of a hyperlink's target range.
+     *
+     * @return offset
+     *
+     * @since 1.0
+     */
+    public int getStartOffset() {
+        return startOffset;
+    }
+
+    /**
+     * The end offset of a hyperlink's target range.
+     *
+     * @return offset
+     *
+     * @since 1.0
+     */
+    public int getEndOffset() {
+        return endOffset;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 5;
+        hash = 29 * hash + Objects.hashCode(this.fileObject);
+        hash = 29 * hash + this.startOffset;
+        hash = 29 * hash + this.endOffset;
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final HyperlinkLocation other = (HyperlinkLocation) obj;
+        if (this.startOffset != other.startOffset) {
+            return false;
+        }
+        if (this.endOffset != other.endOffset) {
+            return false;
+        }
+        if (!Objects.equals(this.fileObject, other.fileObject)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "HyperlinkLocation{" + "fileObject=" + fileObject + ", startOffset=" + startOffset + ", endOffset=" + endOffset + '}';
+    }
+
+    /**
+     * Resolves a hyperlink at the given document offset and returns its target
+     * location(s).
+     *
+     * @param doc document on which to operate.
+     * @param offset offset within document
+     * @return target location(s)
+     *
+     * @since 1.0
+     */
+    @NonNull
+    public static CompletableFuture<List<HyperlinkLocation>> resolve(@NonNull final Document doc, final int offset) {
+        MimePath mimePath = MimePath.parse(DocumentUtilities.getMimeType(doc));
+        CompletableFuture<HyperlinkLocation>[] futures = MimeLookup.getLookup(mimePath).lookupAll(HyperlinkLocationProvider.class).stream()
+                .map(provider -> provider.getHyperlinkLocation(doc, offset)).toArray(CompletableFuture[]::new);
+        return CompletableFuture.allOf(futures).thenApply(value -> {
+            List<HyperlinkLocation> locations = new ArrayList<>(futures.length);
+            for (CompletableFuture<HyperlinkLocation> future : futures) {
+                HyperlinkLocation location = future.getNow(null);
+                if (location != null) {
+                    locations.add(location);
+                }
+            }
+            return locations;
+        });
+    }
+}
diff --git a/ide/api.lsp/src/org/netbeans/api/lsp/TextEdit.java b/ide/api.lsp/src/org/netbeans/api/lsp/TextEdit.java
new file mode 100644
index 0000000..2ce85b5
--- /dev/null
+++ b/ide/api.lsp/src/org/netbeans/api/lsp/TextEdit.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.api.lsp;
+
+import org.netbeans.api.annotations.common.NonNull;
+
+/**
+ * Represents a textual edit applicable to a text document.
+ *
+ * @author Dusan Balek
+ * @since 1.0
+ */
+public final class TextEdit {
+
+    private final int start;
+    private final int end;
+    private final String newText;
+
+    public TextEdit(int start, int end, @NonNull String newText) {
+        this.start = start;
+        this.end = end;
+        this.newText = newText;
+    }
+
+    /**
+     * The start offset of the text document range to be manipulated. To insert
+     * text into a document create edit where {@code startOffset == endOffset}.
+     *
+     * @since 1.0
+     */
+    public int getStartOffset() {
+        return start;
+    }
+
+    /**
+     * The end offset of the text document range to be manipulated. To insert
+     * text into a document create edit where {@code startOffset == endOffset}.
+     *
+     * @since 1.0
+     */
+    public int getEndOffset() {
+        return end;
+    }
+
+    /**
+     * The string to be inserted. For delete operations use an empty string.
+     *
+     * @since 1.0
+     */
+    @NonNull
+    public String getNewText() {
+        return newText;
+    }
+}
diff --git a/ide/api.lsp/src/org/netbeans/modules/lsp/CompletionAccessor.java b/ide/api.lsp/src/org/netbeans/modules/lsp/CompletionAccessor.java
new file mode 100644
index 0000000..fddfa49
--- /dev/null
+++ b/ide/api.lsp/src/org/netbeans/modules/lsp/CompletionAccessor.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.lsp;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.api.lsp.Completion;
+import org.netbeans.api.lsp.TextEdit;
+import org.openide.util.Exceptions;
+import org.openide.util.Parameters;
+
+
+public abstract class CompletionAccessor {
+
+    private static volatile CompletionAccessor DEFAULT;
+
+    public static synchronized CompletionAccessor getDefault() {
+        CompletionAccessor instance = DEFAULT;
+        if (instance == null) {
+            Class<?> c = Completion.class;
+            try {
+                Class.forName(c.getName(), true, c.getClassLoader());
+                instance = DEFAULT;
+                assert instance != null;
+            } catch (Exception ex) {
+                Exceptions.printStackTrace(ex);
+            }
+        }
+        return instance;
+    }
+
+    public static void setDefault(@NonNull final CompletionAccessor accessor) {
+        Parameters.notNull("accessor", accessor);   //NOI18N
+        if (DEFAULT != null) {
+            throw new IllegalStateException("Accessor already initialized");
+        }
+        DEFAULT = accessor;
+    }
+
+    public abstract Completion createCompletion(String label, Completion.Kind kind, List<Completion.Tag> tags, CompletableFuture<String> detail, CompletableFuture<String> documentation,
+            boolean preselect, String sortText, String filterText, String insertText, Completion.TextFormat insertTextFormat,
+            TextEdit textEdit, CompletableFuture<List<TextEdit>> additionalTextEdits, List<Character> commitCharacters);
+}
diff --git a/ide/api.lsp/src/org/netbeans/modules/lsp/HyperlinkLocationAccessor.java b/ide/api.lsp/src/org/netbeans/modules/lsp/HyperlinkLocationAccessor.java
new file mode 100644
index 0000000..5067c69
--- /dev/null
+++ b/ide/api.lsp/src/org/netbeans/modules/lsp/HyperlinkLocationAccessor.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.lsp;
+
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.api.lsp.HyperlinkLocation;
+import org.openide.filesystems.FileObject;
+import org.openide.util.Exceptions;
+import org.openide.util.Parameters;
+
+
+public abstract class HyperlinkLocationAccessor {
+
+    private static volatile HyperlinkLocationAccessor DEFAULT;
+
+    public static synchronized HyperlinkLocationAccessor getDefault() {
+        HyperlinkLocationAccessor instance = DEFAULT;
+        if (instance == null) {
+            Class<?> c = HyperlinkLocation.class;
+            try {
+                Class.forName(c.getName(), true, c.getClassLoader());
+                instance = DEFAULT;
+                assert instance != null;
+            } catch (Exception ex) {
+                Exceptions.printStackTrace(ex);
+            }
+        }
+        return instance;
+    }
+
+    public static void setDefault(@NonNull final HyperlinkLocationAccessor accessor) {
+        Parameters.notNull("accessor", accessor);   //NOI18N
+        DEFAULT = accessor;
+    }
+
+    public abstract HyperlinkLocation createHyperlinkLocation(@NonNull final FileObject fileObject, int startOffset, int endOffset);
+}
diff --git a/ide/api.lsp/src/org/netbeans/spi/lsp/CompletionCollector.java b/ide/api.lsp/src/org/netbeans/spi/lsp/CompletionCollector.java
new file mode 100644
index 0000000..8691e3c
--- /dev/null
+++ b/ide/api.lsp/src/org/netbeans/spi/lsp/CompletionCollector.java
@@ -0,0 +1,358 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.spi.lsp;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+import javax.swing.text.Document;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.api.annotations.common.NullAllowed;
+import org.netbeans.api.lsp.Completion;
+import org.netbeans.api.lsp.TextEdit;
+import org.netbeans.modules.lsp.CompletionAccessor;
+import org.netbeans.spi.editor.mimelookup.MimeLocation;
+
+/**
+ * Interface for computing and collecting completions. Clients can use this interface
+ * to collect completions and send them for presentation outside of NetBeans using
+ * the Language Server Protocol. Implementations of the interface should be registered
+ * in MimeLookup.
+ * <pre>
+ *
+ *  {@code @MimeRegistration(mimeType = "text/foo", service = CompletionCollector.class)
+ *   public class FooCompletionCollector implements CompletionCollector {
+ *     ...
+ *   }
+ *  }
+ * </pre>
+ *
+ * @author Dusan Balek
+ * @since 1.0
+ */
+@MimeLocation(subfolderName = "CompletionCollectors")
+public interface CompletionCollector {
+
+    /**
+     * Computes and collects completions for a document at a given offset.
+     *
+     * @param doc a text document
+     * @param offset an offset inside the text document
+     * @param context an optional completion context
+     * @param consumer an operation accepting collected completions
+     *
+     * @return true if the list of collected completion is complete
+     *
+     * @since 1.0
+     */
+    public boolean collectCompletions(@NonNull Document doc, int offset, @NullAllowed Completion.Context context, @NonNull Consumer<Completion> consumer);
+
+    /**
+     * Creates a builder for {@link Completion} instances.
+     *
+     * @param label the label of the completion
+     * @return newly created builder
+     *
+     * @since 1.0
+     */
+    public static Builder newBuilder(@NonNull String label) {
+        return new Builder(label);
+    }
+
+    /**
+     * Builder for {@link Completion} instances. Its usage can be illustrated by:
+     * {@codesnippet CompletionTest.FooCompletionCollector#builder}
+     *
+     * @since 1.0
+     */
+    public static final class Builder {
+
+        private String label;
+        private Completion.Kind kind;
+        private List<Completion.Tag> tags;
+        private CompletableFuture<String> detail;
+        private CompletableFuture<String> documentation;
+        private boolean preselect;
+        private String sortText;
+        private String filterText;
+        private String insertText;
+        private Completion.TextFormat insertTextFormat;
+        private TextEdit textEdit;
+        private CompletableFuture<List<TextEdit>> additionalTextEdits;
+        private List<Character> commitCharacters;
+
+        private Builder(@NonNull String label) {
+            this.label = label;
+        }
+
+        /**
+         * The label of this completion. By default also the text that is inserted
+         * when selecting this completion.
+         *
+         * @since 1.0
+         */
+        @NonNull
+        public Builder label(@NonNull String label) {
+            this.label = label;
+            return this;
+        }
+
+        /**
+         * The kind of this completion.
+         *
+         * @since 1.0
+         */
+        @NonNull
+        public Builder kind(@NonNull Completion.Kind kind) {
+            this.kind = kind;
+            return this;
+        }
+
+        /**
+         * Adds tag for this completion.
+         *
+         * @since 1.0
+         */
+        @NonNull
+        public Builder addTag(@NonNull Completion.Tag tag) {
+            if (this.tags == null) {
+                this.tags = new ArrayList<>();
+            }
+            this.tags.add(tag);
+            return this;
+        }
+
+        /**
+         * A human-readable string with additional information about this completion,
+         * like type or symbol information. If computing of a full detail is expensive,
+         * user should use {@link #detail(java.util.function.Supplier)} to defer
+         * computation to the subsequent {@code completionItem/resolve} request.
+         *
+         * @since 1.0
+         */
+        @NonNull
+        public Builder detail(@NonNull String detail) {
+            this.detail = CompletableFuture.completedFuture(detail);
+            return this;
+        }
+
+        /**
+         * A human-readable string with additional information about this completion,
+         * like type or symbol information. Use this method to defer computation
+         * of a full detail to the subsequent {@code completionItem/resolve} request.
+         *
+         * @since 1.0
+         */
+        @NonNull
+        public Builder detail(@NonNull Supplier<String> detail) {
+            this.detail = new LazyCompletableFuture<>(detail);
+            return this;
+        }
+
+        /**
+         * A human-readable string that represents a doc-comment. An HTML format
+         * is supported. If computing of a full documentation is expensive,
+         * user should use {@link #documentation(java.util.function.Supplier)} to
+         * defer computation to the subsequent {@code completionItem/resolve} request.
+         *
+         * @since 1.0
+         */
+        @NonNull
+        public Builder documentation(@NonNull String documentation) {
+            this.documentation = CompletableFuture.completedFuture(documentation);
+            return this;
+        }
+
+        /**
+         * A human-readable string that represents a doc-comment. An HTML format
+         * is supported. Use this method to defer computation of a full documentation
+         * to the subsequent {@code completionItem/resolve} request.
+         *
+         * @since 1.0
+         */
+        @NonNull
+        public Builder documentation(@NonNull Supplier<String> documentation) {
+            this.documentation = new LazyCompletableFuture<>(documentation);
+            return this;
+        }
+
+        /**
+         * Select this completion when showing.
+         *
+         * @since 1.0
+         */
+        @NonNull
+        public Builder preselect(boolean preselect) {
+            this.preselect = preselect;
+            return this;
+        }
+
+        /**
+         * A string that should be used when comparing this completion with other
+         * completions. When {@code null} the label is used as the sort text.
+         *
+         * @since 1.0
+         */
+        @NonNull
+        public Builder sortText(@NonNull String sortText) {
+            this.sortText = sortText;
+            return this;
+        }
+
+        /**
+         * A string that should be used when filtering a set of completions.
+         * When {@code null} the label is used as the filter.
+         *
+         * @since 1.0
+         */
+        @NonNull
+        public Builder filterText(@NonNull String filterText) {
+            this.filterText = filterText;
+            return this;
+        }
+
+        /**
+         * A string that should be inserted into a document when selecting
+         * this completion. When {@code null} the label is used as the insert text.
+         *
+         * @since 1.0
+         */
+        @NonNull
+        public Builder insertText(@NonNull String insertText) {
+            this.insertText = insertText;
+            this.textEdit = null;
+            return this;
+        }
+
+        /**
+         * The format of the insert text. The format applies to both the
+         * {@code insertText} property and the {@code newText} property of a provided
+         * {@code textEdit}. If omitted defaults to {@link TextFormat#PlainText}.
+         *
+         * @since 1.0
+         */
+        @NonNull
+        public Builder insertTextFormat(@NonNull Completion.TextFormat insertTextFormat) {
+            this.insertTextFormat = insertTextFormat;
+            return this;
+        }
+
+        /**
+         * An edit which is applied to a document when selecting this completion.
+         * When an edit is provided the value of {@code insertText} is ignored.
+         * The range of the edit must be a single line range and it must
+         * contain the position at which completion has been requested.
+         *
+         * @since 1.0
+         */
+        @NonNull
+        public Builder textEdit(@NonNull TextEdit textEdit) {
+            this.textEdit = textEdit;
+            this.insertText = null;
+            return this;
+        }
+
+        /**
+         * A list of additional text edits that are applied when selecting this
+         * completion. Edits must not overlap (including the same insert position)
+         * with the main edit nor with themselves.
+         * Additional text edits should be used to change text unrelated to the
+         * current cursor position (for example adding an import statement at the
+         * top of the file if the completion item will insert an unqualified type).
+         * If computing of the additional text edits is expensive, user should use
+         * {@link #additionalTextEdits(java.util.function.Supplier)} to defer
+         * computation to the subsequent {@code completionItem/resolve} request.
+         *
+         * @since 1.0
+         */
+        @NonNull
+        public Builder additionalTextEdits(@NonNull List<TextEdit> additionalTextEdits) {
+            this.additionalTextEdits = CompletableFuture.completedFuture(additionalTextEdits);
+            return this;
+        }
+
+        /**
+         * A list of additional text edits that are applied when selecting this
+         * completion. Edits must not overlap (including the same insert position)
+         * with the main edit nor with themselves.
+         * Additional text edits should be used to change text unrelated to the
+         * current cursor position (for example adding an import statement at the
+         * top of the file if the completion item will insert an unqualified type).
+         * Use this method to defer computation of the additional text edits to
+         * the subsequent {@code completionItem/resolve} request.
+         *
+         * @since 1.0
+         */
+        @NonNull
+        public Builder additionalTextEdits(@NonNull Supplier<List<TextEdit>> additionalTextEdits) {
+            this.additionalTextEdits = new LazyCompletableFuture<>(additionalTextEdits);
+            return this;
+        }
+
+        /**
+         * Adds character that when pressed while this completion is active will
+         * accept it first and then type that character.
+         *
+         * @since 1.0
+         */
+        @NonNull
+        public Builder addCommitCharacter(char commitCharacter) {
+            if (this.commitCharacters == null) {
+                this.commitCharacters = new ArrayList<>();
+            }
+            this.commitCharacters.add(commitCharacter);
+            return this;
+        }
+
+        /**
+         * Builds completion.
+         *
+         * @since 1.0
+         */
+        @NonNull
+        public Completion build() {
+            return CompletionAccessor.getDefault().createCompletion(label, kind,
+                    tags, detail, documentation, preselect, sortText, filterText,
+                    insertText, insertTextFormat, textEdit, additionalTextEdits,
+                    commitCharacters);
+        }
+
+        private static class LazyCompletableFuture<T> extends CompletableFuture<T> {
+
+            private final Supplier<T> supplier;
+
+            private LazyCompletableFuture(Supplier<T> supplier) {
+                this.supplier = supplier;
+            }
+
+            @Override
+            public T get() throws InterruptedException, ExecutionException {
+                try {
+                    this.complete(supplier.get());
+                } catch (Exception ex) {
+                    this.completeExceptionally(ex);
+                }
+                return super.get();
+            }
+        }
+    }
+}
diff --git a/ide/api.lsp/src/org/netbeans/spi/lsp/HyperlinkLocationProvider.java b/ide/api.lsp/src/org/netbeans/spi/lsp/HyperlinkLocationProvider.java
new file mode 100644
index 0000000..48d760e
--- /dev/null
+++ b/ide/api.lsp/src/org/netbeans/spi/lsp/HyperlinkLocationProvider.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.spi.lsp;
+
+import org.netbeans.api.lsp.HyperlinkLocation;
+import java.util.concurrent.CompletableFuture;
+import javax.swing.text.Document;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.modules.lsp.HyperlinkLocationAccessor;
+import org.netbeans.spi.editor.mimelookup.MimeLocation;
+import org.openide.filesystems.FileObject;
+
+/**
+ * Interface for resolving hyperlink locations. Implementations of the interface
+ * should be registered in MimeLookup.
+ * <pre>
+ *
+ *  {@code @MimeRegistration(mimeType = "text/foo", service = HyperlinkLocationProvider.class)
+ *   public class FooHyperlinkLocationProvider implements HyperlinkLocationProvider {
+ *     ...
+ *   }
+ *  }
+ * </pre>
+ *
+ * @author Dusan Balek
+ * @since 1.0
+ */
+@MimeLocation(subfolderName = "HyperlinkLocationProviders")
+public interface HyperlinkLocationProvider {
+
+    /**
+     * Resolves a hyperlink at the given document offset and returns its
+     * target location.
+     *
+     * @param doc document on which to operate.
+     * @param offset offset within document
+     * @return target location
+     *
+     * @since 1.0
+     */
+    CompletableFuture<HyperlinkLocation> getHyperlinkLocation(@NonNull Document doc, int offset);
+
+    /**
+     * Creates {@link HyperlinkLocation} instances.
+     *
+     * @param fileObject target file object of the hyperlink
+     * @param startOffset start offset of the hyperlink's target range
+     * @param endOffset end offset of the hyperlink's target range
+     * @return new created instance
+     *
+     * @since 1.0
+     */
+    public static HyperlinkLocation createHyperlinkLocation(@NonNull FileObject fileObject, int startOffset, int endOffset) {
+        return HyperlinkLocationAccessor.getDefault().createHyperlinkLocation(fileObject, startOffset, endOffset);
+    }
+}
diff --git a/ide/api.lsp/test/unit/src/org/netbeans/api/lsp/CompletionTest.java b/ide/api.lsp/test/unit/src/org/netbeans/api/lsp/CompletionTest.java
new file mode 100644
index 0000000..1c0b640
--- /dev/null
+++ b/ide/api.lsp/test/unit/src/org/netbeans/api/lsp/CompletionTest.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.api.lsp;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.DefaultStyledDocument;
+import javax.swing.text.Document;
+import org.netbeans.api.editor.mimelookup.MimePath;
+import org.netbeans.api.editor.mimelookup.test.MockMimeLookup;
+import org.netbeans.junit.NbTestCase;
+import org.netbeans.spi.lsp.CompletionCollector;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+public class CompletionTest extends NbTestCase {
+
+    public CompletionTest(String name) {
+        super(name);
+    }
+
+    @Override
+    public void setUp () throws Exception {
+        super.setUp();
+        clearWorkDir();
+        MockMimeLookup.setInstances (MimePath.get ("text/foo"), new FooCompletionCollector());
+    }
+
+    public void testCompletionCollect() {
+        Document doc = createDocument("text/foo", "");
+        int offset = 0;
+        // BEGIN: CompletionTest#testCompletionCollect
+
+        // Compute and collect completions for a document at a given offset
+        boolean isComplete = Completion.collect(doc, offset, null, completion -> {
+
+            // completion should never be 'null'
+            assertNotNull(completion);
+
+            // getting completion 'label'
+            String label = completion.getLabel();
+            assertEquals("label", label);
+
+            // getting optional completion 'detail'
+            CompletableFuture<String> detail = completion.getDetail();
+            // check for 'null' value
+            if (detail != null) {
+                // value should be already computed
+                assertTrue(detail.isDone());
+                // getting the value
+                String value = detail.getNow(null);
+                assertEquals("detail", value);
+            }
+
+            // getting optional completion 'documentation'
+            CompletableFuture<String> documentation = completion.getDocumentation();
+            // check for 'null' value
+            if (documentation != null) {
+                // value computation should be deferred
+                assertFalse(documentation.isDone());
+                // getting the value
+                try {
+                    String value = documentation.get();
+                    assertEquals("documentation", value);
+                } catch (Exception ex) {
+                    Exceptions.printStackTrace(ex);
+                }
+            }
+        });
+
+        // END: CompletionTest#testCompletionCollect
+        assertTrue(isComplete);
+    }
+
+    private Document createDocument(String mimeType, String contents) {
+        Document doc = new DefaultStyledDocument();
+        doc.putProperty("mimeType", mimeType);
+        try {
+            doc.insertString(0, contents, null);
+            return doc;
+        } catch (BadLocationException ble) {
+            throw new IllegalStateException(ble);
+        }
+    }
+
+    private static class FooCompletionCollector implements CompletionCollector {
+
+        @Override
+        public boolean collectCompletions(Document doc, int offset, Completion.Context context, Consumer<Completion> consumer) {
+            // BEGIN: CompletionTest.FooCompletionCollector#builder
+
+            // Create a builder for creating 'Completion' instance providing its 'label'
+            Completion c = CompletionCollector.newBuilder("label")
+
+                    // set completion detail
+                    .detail("detail")
+
+                    // set completion documentation with deffered computation
+                    .documentation(() -> {
+                        return "documentation";
+                    })
+
+                    // create a new 'Completion' instance
+                    .build();
+
+            // END: CompletionTest.FooCompletionCollector#builder
+            consumer.accept(c);
+            return true;
+        }
+    }
+}
diff --git a/ide/csl.api/src/org/netbeans/modules/csl/editor/completion/GsfCompletionDoc.java b/ide/csl.api/src/org/netbeans/modules/csl/editor/completion/GsfCompletionDoc.java
index b922d1f..9be44e2 100644
--- a/ide/csl.api/src/org/netbeans/modules/csl/editor/completion/GsfCompletionDoc.java
+++ b/ide/csl.api/src/org/netbeans/modules/csl/editor/completion/GsfCompletionDoc.java
@@ -101,15 +101,12 @@ public class GsfCompletionDoc implements CompletionDocumentation {
                 this.content = completer.document(controller, elementHandle);
             }
         }
-
-        if (this.content == null) {
-            Completion.get().hideDocumentation();
-        }
     }
 
     public static final GsfCompletionDoc create(ParserResult controller,
         ElementHandle elementHandle, Callable<Boolean> cancel) {
-        return new GsfCompletionDoc(controller, elementHandle, null, cancel);
+        GsfCompletionDoc doc = new GsfCompletionDoc(controller, elementHandle, null, cancel);
+        return doc.content != null ? doc : null;
     }
 
     public String getText() {
diff --git a/ide/csl.api/src/org/netbeans/modules/csl/editor/completion/GsfCompletionProvider.java b/ide/csl.api/src/org/netbeans/modules/csl/editor/completion/GsfCompletionProvider.java
index 766bda6..9c3d961 100644
--- a/ide/csl.api/src/org/netbeans/modules/csl/editor/completion/GsfCompletionProvider.java
+++ b/ide/csl.api/src/org/netbeans/modules/csl/editor/completion/GsfCompletionProvider.java
@@ -561,7 +561,7 @@ public class GsfCompletionProvider implements CompletionProvider {
                                     }
                                 });
                                 // TODO - find some way to show the multiple overloaded methods?
-                                if (documentation.getText() != null && documentation.getText().length() > 0) {
+                                if (documentation != null && documentation.getText() != null && documentation.getText().length() > 0) {
                                     // Make sure we at least pick an alternative that has documentation
                                     break;
                                 }
diff --git a/ide/languages.yaml/src/org/netbeans/modules/languages/yaml/YamlCompletion.java b/ide/languages.yaml/src/org/netbeans/modules/languages/yaml/YamlCompletion.java
index 4ad7da1..6ff3089 100644
--- a/ide/languages.yaml/src/org/netbeans/modules/languages/yaml/YamlCompletion.java
+++ b/ide/languages.yaml/src/org/netbeans/modules/languages/yaml/YamlCompletion.java
@@ -152,17 +152,19 @@ public class YamlCompletion implements CodeCompletionHandler {
             StringBuilder sb = new StringBuilder();
 
             try {
-                is = new BufferedInputStream(YamlCompletion.class.getResourceAsStream("refcard.html"));
-                while (true) {
-                    int c = is.read();
+                InputStream stream = YamlCompletion.class.getResourceAsStream("refcard.html");
+                if (stream != null) {
+                    is = new BufferedInputStream(stream);
+                    while (true) {
+                        int c = is.read();
 
-                    if (c == -1) {
-                        break;
-                    }
+                        if (c == -1) {
+                            break;
+                        }
 
-                    sb.append((char) c);
+                        sb.append((char) c);
+                    }
                 }
-
                 if (sb.length() > 0) {
                     refcard = sb.toString();
                 }
diff --git a/ide/languages.yaml/src/org/netbeans/modules/languages/yaml/YamlParser.java b/ide/languages.yaml/src/org/netbeans/modules/languages/yaml/YamlParser.java
index 6ea7368..6b6d85b 100644
--- a/ide/languages.yaml/src/org/netbeans/modules/languages/yaml/YamlParser.java
+++ b/ide/languages.yaml/src/org/netbeans/modules/languages/yaml/YamlParser.java
@@ -31,10 +31,14 @@ import java.util.regex.Pattern;
 import javax.swing.event.ChangeListener;
 import org.jruby.util.ByteList;
 import org.jvyamlb.Composer;
+import org.jvyamlb.ParserImpl;
 import org.jvyamlb.PositioningComposerImpl;
 import org.jvyamlb.PositioningParserImpl;
 import org.jvyamlb.PositioningScannerImpl;
 import org.jvyamlb.ResolverImpl;
+import org.jvyamlb.YAMLConfig;
+import org.jvyamlb.events.Event;
+import org.jvyamlb.exceptions.PositionedComposerException;
 import org.jvyamlb.exceptions.PositionedParserException;
 import org.jvyamlb.exceptions.PositionedScannerException;
 import org.jvyamlb.nodes.Node;
@@ -194,6 +198,7 @@ public class YamlParser extends Parser {
         source = replaceCommonSpecialCharacters(source);
         source = replaceInlineRegexBrackets(source);
 
+        List<Node> nodes = new ArrayList<Node>();
         try {
             if (isTooLarge(source)) {
                 return resultForTooLargeFile(snapshot);
@@ -248,8 +253,56 @@ public class YamlParser extends Parser {
                 byteList = new ByteList(out.toByteArray());
             }
 
-            Composer composer = new PositioningComposerImpl(new PositioningParserImpl(new PositioningScannerImpl(byteList)), new ResolverImpl());
-            List<Node> nodes = new ArrayList<Node>();
+            final List<DefaultError> errors = new ArrayList<>();
+            PositioningScannerImpl scanner = new PositioningScannerImpl(byteList) {
+                @Override
+                protected void scannerException(String when, String what, String note) {
+                    try {
+                        super.scannerException(when, what, note);
+                    } catch (PositionedScannerException pse) {
+                        int pos = pse.getPosition().offset;
+                        String message = pse.getMessage();
+                        if (message != null && message.length() > 0) {
+                            errors.add(processError(message, snapshot, pos));
+                        }
+                        // Move local pointer to the next char to make progress
+                        this.pointer++;
+                    }
+                }
+            };
+            PositioningParserImpl parser = new PositioningParserImpl(scanner) {
+                @Override
+                protected ParserImpl.ProductionEnvironment getEnvironment(YAMLConfig cfg) {
+                    return new PositioningProductionEnvironment(cfg) {
+                        @Override
+                        protected void parserException(String when, String what, String note, org.jvyamlb.tokens.Token t) {
+                            try {
+                                super.parserException(when, what, note, t);
+                            } catch (PositionedParserException ppe) {
+                                int pos = ppe.getPosition().offset;
+                                String message = ppe.getMessage();
+                                if (message != null && message.length() > 0) {
+                                    errors.add(processError(message, snapshot, pos));
+                                }
+                            }
+                        }
+                    };
+                }
+            };
+            Composer composer = new PositioningComposerImpl(parser, new ResolverImpl()) {
+                @Override
+                protected void composerException(String when, String what, String note, Event e) {
+                    try {
+                        super.composerException(when, what, note, e);
+                    } catch (PositionedComposerException pce) {
+                        int pos = pce.getPosition().offset;
+                        String message = pce.getMessage();
+                        if (message != null && message.length() > 0) {
+                            errors.add(processError(message, snapshot, pos));
+                        }
+                    }
+                }
+            };
             Iterator iterator = composer.eachNode();
             while (iterator.hasNext()) {
                 Node node = (Node) iterator.next();
@@ -259,59 +312,39 @@ public class YamlParser extends Parser {
                 nodes.add(node);
             }
 
-            //Object yaml = YAML.load(stream);
-            return new YamlParserResult(nodes, this, snapshot, true, byteToUtf8, utf8toByte);
-        } catch (Exception ex) {
-            int pos = 0;
-            if (ex instanceof PositionedParserException) {
-                PositionedParserException ppe = (PositionedParserException) ex;
-                pos = ppe.getPosition().offset;
-            } else if (ex instanceof PositionedScannerException) {
-                PositionedScannerException pse = (PositionedScannerException) ex;
-                pos = pse.getPosition().offset;
-                // The scanner possition is on the next token. We need to reallocate it
-                // on the previous token.
-                TokenHierarchy th = snapshot.getTokenHierarchy();
-                if (th != null) {
-                    TokenSequence ts = th.tokenSequence();
-                    if (ts != null) {
-                        ts.move(pos);
-                        ts.moveNext();
-                        Token token = ts.token();
-                        // don't move the error, when there is more values on the line. See #171633
-                        if (token != null && token.text().toString().indexOf('{') == -1 && ts.movePrevious()) {
-                            pos = ts.offset();
-                        }
-                    }
-                }
+            YamlParserResult result = new YamlParserResult(nodes, this, snapshot, true, byteToUtf8, utf8toByte);
+            if (!errors.isEmpty()) {
+                result.addError(errors.get(0));
             }
-
+            return result;
+        } catch (Exception ex) {
             YamlParserResult result = new YamlParserResult(Collections.<Node>emptyList(), this, snapshot, false, null, null);
             String message = ex.getMessage();
             if (message != null && message.length() > 0) {
-                // Strip off useless prefixes to make errors more readable
-                if (message.startsWith("ScannerException null ")) { // NOI18N
-                    message = message.substring(22);
-                } else if (message.startsWith("ParserException ")) { // NOI18N
-                    message = message.substring(16);
-                }
-                // Capitalize sentences
-                char firstChar = message.charAt(0);
-                char upcasedChar = Character.toUpperCase(firstChar);
-                if (firstChar != upcasedChar) {
-                    message = upcasedChar + message.substring(1);
-                }
-
-                // FIXME this can violate contract of DefaultError (null fo)
-                DefaultError error = new DefaultError(null, message, null, snapshot.getSource().getFileObject(),
-                        pos, pos, Severity.ERROR);
-                result.addError(error);
+                result.addError(processError(message, snapshot, 0));
             }
-
             return result;
         }
     }
 
+    private DefaultError processError(String message, Snapshot snapshot, int pos) {
+        // Strip off useless prefixes to make errors more readable
+        if (message.startsWith("ScannerException null ")) { // NOI18N
+            message = message.substring(22);
+        } else if (message.startsWith("ParserException ")) { // NOI18N
+            message = message.substring(16);
+        }
+        // Capitalize sentences
+        char firstChar = message.charAt(0);
+        char upcasedChar = Character.toUpperCase(firstChar);
+        if (firstChar != upcasedChar) {
+            message = upcasedChar + message.substring(1);
+        }
+        // FIXME this can violate contract of DefaultError (null fo)
+        return new DefaultError(null, message, null, snapshot.getSource().getFileObject(),
+                pos, pos, Severity.ERROR);
+    }
+
     @Override
     public void parse(Snapshot snapshot, Task task, SourceModificationEvent event) throws ParseException {
 
diff --git a/ide/libs.bytelist/external/binaries-list b/ide/libs.bytelist/external/binaries-list
index 0e0b70c1..e3ec14a 100644
--- a/ide/libs.bytelist/external/binaries-list
+++ b/ide/libs.bytelist/external/binaries-list
@@ -14,5 +14,4 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-80294E59315B314D57782DC37F983AE5B29C2E4C org.jruby.extras:bytelist:1.0.15
-E2C76A19F00128BB1806207E2989139BFB45F49D org.jruby.jcodings:jcodings:1.0.18
+80294E59315B314D57782DC37F983AE5B29C2E4C org.jruby.extras:bytelist:1.0.15
\ No newline at end of file
diff --git a/ide/libs.bytelist/nbproject/project.properties b/ide/libs.bytelist/nbproject/project.properties
index 20a62cb..4e011ca 100644
--- a/ide/libs.bytelist/nbproject/project.properties
+++ b/ide/libs.bytelist/nbproject/project.properties
@@ -17,5 +17,4 @@
 
 is.autoload=true
 release.external/bytelist-1.0.15.jar=modules/ext/bytelist-1.0.15.jar
-release.external/jcodings-1.0.18.jar=modules/ext/jcodings-1.0.18.jar
-spec.version.base=0.41.0
+spec.version.base=0.42.0
diff --git a/ide/libs.bytelist/nbproject/project.xml b/ide/libs.bytelist/nbproject/project.xml
index b735374..92cc333 100644
--- a/ide/libs.bytelist/nbproject/project.xml
+++ b/ide/libs.bytelist/nbproject/project.xml
@@ -24,7 +24,15 @@
     <configuration>
         <data xmlns="http://www.netbeans.org/ns/nb-module-project/2">
             <code-name-base>org.netbeans.libs.bytelist</code-name-base>
-            <module-dependencies/>
+            <module-dependencies>
+                <dependency>
+                    <code-name-base>org.netbeans.libs.jcodings</code-name-base>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <specification-version>0.1</specification-version>
+                    </run-dependency>
+                </dependency>
+            </module-dependencies>
             <!--            
             <friend-packages>
                 <friend>org.jruby</friend>
@@ -39,10 +47,6 @@
                 <package>org.jruby.util</package>
             </public-packages>
             <class-path-extension>
-                <runtime-relative-path>ext/jcodings-1.0.18.jar</runtime-relative-path>
-                <binary-origin>external/jcodings-1.0.18.jar</binary-origin>
-            </class-path-extension>
-            <class-path-extension>
                 <runtime-relative-path>ext/bytelist-1.0.15.jar</runtime-relative-path>
                 <binary-origin>external/bytelist-1.0.15.jar</binary-origin>
             </class-path-extension>
diff --git a/ide/libs.jcodings/build.xml b/ide/libs.jcodings/build.xml
new file mode 100644
index 0000000..c6a8ce1
--- /dev/null
+++ b/ide/libs.jcodings/build.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<project name="ide/libs.jcodings" default="build" basedir=".">
+    <import file="../../nbbuild/templates/projectized.xml"/>
+</project>
diff --git a/ide/libs.bytelist/external/binaries-list b/ide/libs.jcodings/external/binaries-list
similarity index 92%
copy from ide/libs.bytelist/external/binaries-list
copy to ide/libs.jcodings/external/binaries-list
index 0e0b70c1..28eb079 100644
--- a/ide/libs.bytelist/external/binaries-list
+++ b/ide/libs.jcodings/external/binaries-list
@@ -14,5 +14,4 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-80294E59315B314D57782DC37F983AE5B29C2E4C org.jruby.extras:bytelist:1.0.15
 E2C76A19F00128BB1806207E2989139BFB45F49D org.jruby.jcodings:jcodings:1.0.18
diff --git a/ide/libs.bytelist/external/jcodings-1.0.18-license.txt b/ide/libs.jcodings/external/jcodings-1.0.18-license.txt
similarity index 100%
rename from ide/libs.bytelist/external/jcodings-1.0.18-license.txt
rename to ide/libs.jcodings/external/jcodings-1.0.18-license.txt
diff --git a/ide/libs.jcodings/manifest.mf b/ide/libs.jcodings/manifest.mf
new file mode 100644
index 0000000..af1e111
--- /dev/null
+++ b/ide/libs.jcodings/manifest.mf
@@ -0,0 +1,4 @@
+Manifest-Version: 1.0
+OpenIDE-Module: org.netbeans.libs.jcodings/1
+OpenIDE-Module-Localizing-Bundle: org/netbeans/libs/jcodings/Bundle.properties
+OpenIDE-Module-Specification-Version: 0.1
diff --git a/ide/libs.bytelist/nbproject/project.properties b/ide/libs.jcodings/nbproject/project.properties
similarity index 90%
copy from ide/libs.bytelist/nbproject/project.properties
copy to ide/libs.jcodings/nbproject/project.properties
index 20a62cb..0c9d012 100644
--- a/ide/libs.bytelist/nbproject/project.properties
+++ b/ide/libs.jcodings/nbproject/project.properties
@@ -16,6 +16,4 @@
 # under the License.
 
 is.autoload=true
-release.external/bytelist-1.0.15.jar=modules/ext/bytelist-1.0.15.jar
 release.external/jcodings-1.0.18.jar=modules/ext/jcodings-1.0.18.jar
-spec.version.base=0.41.0
diff --git a/ide/libs.bytelist/nbproject/project.xml b/ide/libs.jcodings/nbproject/project.xml
similarity index 64%
copy from ide/libs.bytelist/nbproject/project.xml
copy to ide/libs.jcodings/nbproject/project.xml
index b735374..09be4f9 100644
--- a/ide/libs.bytelist/nbproject/project.xml
+++ b/ide/libs.jcodings/nbproject/project.xml
@@ -22,30 +22,16 @@
 <project xmlns="http://www.netbeans.org/ns/project/1">
     <type>org.netbeans.modules.apisupport.project</type>
     <configuration>
-        <data xmlns="http://www.netbeans.org/ns/nb-module-project/2">
-            <code-name-base>org.netbeans.libs.bytelist</code-name-base>
+        <data xmlns="http://www.netbeans.org/ns/nb-module-project/3">
+            <code-name-base>org.netbeans.libs.jcodings</code-name-base>
             <module-dependencies/>
-            <!--            
-            <friend-packages>
-                <friend>org.jruby</friend>
-                <friend>org.netbeans.modules.libs.jvyamlb</friend>
-                <friend>org.netbeans.modules.languages.yaml</friend>
-                <friend>org.netbeans.modules.ruby</friend>
-                <friend>org.netbeans.modules.ruby.hints</friend>
-                <package>org.jruby.util</package>
-            </friend-packages>
--->
             <public-packages>
-                <package>org.jruby.util</package>
+                <subpackages>org.jcodings</subpackages>
             </public-packages>
             <class-path-extension>
                 <runtime-relative-path>ext/jcodings-1.0.18.jar</runtime-relative-path>
                 <binary-origin>external/jcodings-1.0.18.jar</binary-origin>
             </class-path-extension>
-            <class-path-extension>
-                <runtime-relative-path>ext/bytelist-1.0.15.jar</runtime-relative-path>
-                <binary-origin>external/bytelist-1.0.15.jar</binary-origin>
-            </class-path-extension>
         </data>
     </configuration>
 </project>
diff --git a/ide/libs.bytelist/nbproject/project.properties b/ide/libs.jcodings/src/org/netbeans/libs/jcodings/Bundle.properties
similarity index 75%
copy from ide/libs.bytelist/nbproject/project.properties
copy to ide/libs.jcodings/src/org/netbeans/libs/jcodings/Bundle.properties
index 20a62cb..b730623 100644
--- a/ide/libs.bytelist/nbproject/project.properties
+++ b/ide/libs.jcodings/src/org/netbeans/libs/jcodings/Bundle.properties
@@ -15,7 +15,8 @@
 # specific language governing permissions and limitations
 # under the License.
 
-is.autoload=true
-release.external/bytelist-1.0.15.jar=modules/ext/bytelist-1.0.15.jar
-release.external/jcodings-1.0.18.jar=modules/ext/jcodings-1.0.18.jar
-spec.version.base=0.41.0
+OpenIDE-Module-Name=JCodings Library
+OpenIDE-Module-Display-Category=Libraries
+OpenIDE-Module-Short-Description=JCodings Library
+OpenIDE-Module-Long-Description=\
+    This module bundles the JCodings library used by TextMate Lexer and the JRuby ByteList.
diff --git a/ide/textmate.lexer/external/binaries-list b/ide/textmate.lexer/external/binaries-list
index bfdb182..4bb066b 100644
--- a/ide/textmate.lexer/external/binaries-list
+++ b/ide/textmate.lexer/external/binaries-list
@@ -14,6 +14,5 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-E2C76A19F00128BB1806207E2989139BFB45F49D org.jruby.jcodings:jcodings:1.0.18
 655CC3ABA1BC9DBDD653F28937BEC16F3E9C4CEC org.jruby.joni:joni:2.1.11
 109763C0803F3EAC2372B4E4A9A0D7BED9CAB5BC eu.doppel-helix.netbeans.lib.tm4e:org.eclipse.tm4e.core:0.4.1-pack1
diff --git a/ide/textmate.lexer/external/jcodings-1.0.18-license.txt b/ide/textmate.lexer/external/jcodings-1.0.18-license.txt
deleted file mode 100644
index cd273db..0000000
--- a/ide/textmate.lexer/external/jcodings-1.0.18-license.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-Name: jcodings
-Version: 1.0.18
-License: MIT-nocopyright
-Description: Needed by TextMate support for Eclipse
-Origin: https://github.com/jruby/jcodings
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/ide/textmate.lexer/nbproject/project.properties b/ide/textmate.lexer/nbproject/project.properties
index 45278cc..442ebd7 100644
--- a/ide/textmate.lexer/nbproject/project.properties
+++ b/ide/textmate.lexer/nbproject/project.properties
@@ -20,6 +20,5 @@ javac.compilerargs=-Xlint -Xlint:-serial
 javadoc.arch=${basedir}/arch.xml
 javadoc.apichanges=${basedir}/apichanges.xml
 release.external/joni-2.1.11.jar=modules/ext/joni-2.1.11.jar
-release.external/jcodings-1.0.18.jar=modules/ext/jcodings-1.0.18.jar
 release.external/org.eclipse.tm4e.core-0.4.1-pack1.jar=modules/ext/org.eclipse.tm4e.core-0.4.1-pack1.jar
-spec.version.base=1.11.0
+spec.version.base=1.12.0
diff --git a/ide/textmate.lexer/nbproject/project.xml b/ide/textmate.lexer/nbproject/project.xml
index ada1613..974264d 100644
--- a/ide/textmate.lexer/nbproject/project.xml
+++ b/ide/textmate.lexer/nbproject/project.xml
@@ -40,6 +40,13 @@
                     </run-dependency>
                 </dependency>
                 <dependency>
+                    <code-name-base>org.netbeans.libs.jcodings</code-name-base>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <specification-version>0.1</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
                     <code-name-base>org.netbeans.modules.editor.lib2</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
@@ -197,10 +204,6 @@
                 <binary-origin>external/joni-2.1.11.jar</binary-origin>
             </class-path-extension>
             <class-path-extension>
-                <runtime-relative-path>ext/jcodings-1.0.18.jar</runtime-relative-path>
-                <binary-origin>external/jcodings-1.0.18.jar</binary-origin>
-            </class-path-extension>
-            <class-path-extension>
                 <runtime-relative-path>ext/org.eclipse.tm4e.core-0.4.1-pack1.jar</runtime-relative-path>
                 <binary-origin>external/org.eclipse.tm4e.core-0.4.1-pack1.jar</binary-origin>
             </class-path-extension>
diff --git a/java/java.editor/nbproject/project.xml b/java/java.editor/nbproject/project.xml
index 45663f5..eaa3a89 100644
--- a/java/java.editor/nbproject/project.xml
+++ b/java/java.editor/nbproject/project.xml
@@ -53,6 +53,15 @@
                     </run-dependency>
                 </dependency>
                 <dependency>
+                    <code-name-base>org.netbeans.api.lsp</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <specification-version>1.0</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
                     <code-name-base>org.netbeans.api.progress</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
@@ -248,7 +257,7 @@
                     <compile-dependency/>
                     <run-dependency>
                         <release-version>1</release-version>
-                        <specification-version>1.20</specification-version>
+                        <specification-version>1.58</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
diff --git a/java/java.editor/src/org/netbeans/modules/editor/java/GoToSupport.java b/java/java.editor/src/org/netbeans/modules/editor/java/GoToSupport.java
index 675511b..287c926 100644
--- a/java/java.editor/src/org/netbeans/modules/editor/java/GoToSupport.java
+++ b/java/java.editor/src/org/netbeans/modules/editor/java/GoToSupport.java
@@ -25,6 +25,7 @@ import com.sun.source.tree.ExpressionTree;
 import com.sun.source.tree.IdentifierTree;
 import com.sun.source.tree.ImportTree;
 import com.sun.source.tree.InstanceOfTree;
+import com.sun.source.tree.LineMap;
 import com.sun.source.tree.MemberSelectTree;
 import com.sun.source.tree.MethodInvocationTree;
 import com.sun.source.tree.MethodTree;
@@ -44,14 +45,18 @@ import com.sun.source.util.Trees;
 import java.awt.Toolkit;
 import java.awt.event.KeyEvent;
 import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.EnumSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.Callable;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -92,6 +97,7 @@ import org.netbeans.api.java.source.ui.ElementOpen;
 import org.netbeans.api.lexer.Token;
 import org.netbeans.api.lexer.TokenHierarchy;
 import org.netbeans.api.lexer.TokenSequence;
+import org.netbeans.api.lsp.HyperlinkLocation;
 import org.netbeans.api.progress.ProgressUtils;
 import org.netbeans.editor.ext.ToolTipSupport;
 import org.netbeans.lib.editor.hyperlink.spi.HyperlinkType;
@@ -103,15 +109,13 @@ import org.netbeans.modules.parsing.api.Source;
 import org.netbeans.modules.parsing.api.UserTask;
 import org.netbeans.modules.parsing.spi.ParseException;
 import org.netbeans.modules.parsing.spi.Parser.Result;
+import org.netbeans.spi.lsp.HyperlinkLocationProvider;
 import org.openide.awt.HtmlBrowser;
 import org.openide.awt.StatusDisplayer;
 import org.openide.filesystems.FileObject;
 import org.openide.loaders.DataObject;
 import org.openide.util.Exceptions;
 import org.openide.util.NbBundle;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.Objects;
 
 /**
  *
@@ -161,6 +165,51 @@ public class GoToSupport {
             throw new IllegalStateException(ex);
         }
     }
+
+    public static CompletableFuture<HyperlinkLocation> getGoToLocation(final Document doc, final int offset) {
+        try {
+            final FileObject fo = getFileObject(doc);
+            if (fo != null) {
+                final GoToTarget[] target = new GoToTarget[1];
+                final LineMap[] lineMap = new LineMap[1];
+
+                ParserManager.parse(Collections.singleton (Source.create(doc)), new UserTask() {
+                    @Override
+                    public void run(ResultIterator resultIterator) throws Exception {
+                        Result res = resultIterator.getParserResult (offset);
+                        CompilationController controller = res != null ? CompilationController.get(res) : null;
+                        if (controller == null || controller.toPhase(Phase.RESOLVED).compareTo(Phase.RESOLVED) < 0) {
+                            return;
+                        }
+
+                        Context resolved = resolveContext(controller, doc, offset, false, false);
+
+                        if (resolved == null) {
+                            target[0] = new GoToTarget(-1, -1, null, null, null, null, null, false);
+                        } else {
+                            target[0] = computeGoToTarget(controller, resolved, offset);
+                        }
+
+                        lineMap[0] = controller.getCompilationUnit().getLineMap();
+                    }
+                });
+                if (target[0] != null && target[0].success) {
+                    if (target[0].offsetToOpen < 0) {
+                        CompletableFuture<ElementOpen.Location> future = ElementOpen.getLocation(target[0].cpInfo, target[0].elementToOpen, target[0].resourceName);
+                        return future.thenApply(location -> {
+                            return location != null ? HyperlinkLocationProvider.createHyperlinkLocation(location.getFileObject(), location.getStartOffset(), location.getEndOffset()) : null;
+                        });
+                    }
+                    int start = target[0].nameSpan != null ? target[0].nameSpan[0] : target[0].offsetToOpen;
+                    int end = target[0].nameSpan != null ? target[0].nameSpan[1] : target[0].endPos;
+                    return CompletableFuture.completedFuture(HyperlinkLocationProvider.createHyperlinkLocation(fo, start, end));
+                }
+            }
+            return CompletableFuture.completedFuture(null);
+        } catch (ParseException ex) {
+            throw new IllegalStateException(ex);
+        }
+    }
     
     private static boolean isError(Element el) {
         return el == null || el.asType() == null || el.asType().getKind() == TypeKind.ERROR;
diff --git a/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionCollector.java b/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionCollector.java
new file mode 100644
index 0000000..0dc17e0
--- /dev/null
+++ b/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionCollector.java
@@ -0,0 +1,548 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.editor.java;
+
+import com.sun.source.tree.Scope;
+import com.sun.source.util.TreePath;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.TypeParameterElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.ExecutableType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
+import javax.swing.text.Document;
+import org.netbeans.api.editor.mimelookup.MimeRegistration;
+import org.netbeans.api.java.lexer.JavaTokenId;
+import org.netbeans.api.java.source.CompilationController;
+import org.netbeans.api.java.source.CompilationInfo;
+import org.netbeans.api.java.source.ElementHandle;
+import org.netbeans.api.java.source.GeneratorUtilities;
+import org.netbeans.api.java.source.JavaSource;
+import org.netbeans.api.java.source.ModificationResult;
+import org.netbeans.api.java.source.Task;
+import org.netbeans.api.java.source.WorkingCopy;
+import org.netbeans.api.java.source.support.ReferencesCount;
+import org.netbeans.api.java.source.ui.ElementJavadoc;
+import org.netbeans.api.lexer.TokenSequence;
+import org.netbeans.api.lsp.Completion;
+import org.netbeans.api.lsp.TextEdit;
+import org.netbeans.modules.java.completion.JavaCompletionTask;
+import org.netbeans.modules.java.editor.codegen.GeneratorUtils;
+import org.netbeans.modules.parsing.api.ParserManager;
+import org.netbeans.modules.parsing.api.ResultIterator;
+import org.netbeans.modules.parsing.api.Source;
+import org.netbeans.modules.parsing.api.UserTask;
+import org.netbeans.modules.parsing.spi.ParseException;
+import org.netbeans.spi.lsp.CompletionCollector;
+import org.openide.filesystems.FileObject;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+@MimeRegistration(mimeType = "text/x-java", service = CompletionCollector.class)
+public class JavaCompletionCollector implements CompletionCollector {
+
+    @Override
+    public boolean collectCompletions(Document doc, int offset, Completion.Context context, Consumer<Completion> consumer) {
+        AtomicBoolean ret = new AtomicBoolean(true);
+        try {
+            ParserManager.parse(Collections.singletonList(Source.create(doc)), new UserTask() {
+                @Override
+                public void run(ResultIterator resultIterator) throws Exception {
+                    TokenSequence<JavaTokenId> ts = resultIterator.getSnapshot().getTokenHierarchy().tokenSequence(JavaTokenId.language());
+                    if (ts.move(offset) == 0 || !ts.moveNext()) {
+                        if (!ts.movePrevious()) {
+                            ts.moveNext();
+                        }
+                    }
+                    int len = offset - ts.offset();
+                    boolean allCompletion = context != null && context.getTriggerKind() == Completion.TriggerKind.TriggerForIncompleteCompletions
+                            || len > 0 && ts.token().length() >= len && ts.token().id() == JavaTokenId.IDENTIFIER;
+                    CompilationController controller = CompilationController.get(resultIterator.getParserResult(ts.offset()));
+                    controller.toPhase(JavaSource.Phase.RESOLVED);
+                    JavaCompletionTask<Completion> task = JavaCompletionTask.create(offset, new ItemFactoryImpl(controller, ts.offset()), allCompletion ? EnumSet.of(JavaCompletionTask.Options.ALL_COMPLETION) : EnumSet.noneOf(JavaCompletionTask.Options.class), () -> false);
+                    task.run(resultIterator);
+                    List<Completion> results = task.getResults();
+                    if (results != null) {
+                        for (Iterator<Completion> it = results.iterator(); it.hasNext();) {
+                            Completion item = it.next();
+                            if (item == null) {
+                                it.remove();
+                            }
+                        }
+                        results.forEach(consumer);
+                    }
+                    if (task.hasAdditionalClasses() || task.hasAdditionalMembers()) {
+                        ret.set(false);
+                    }
+                }
+            });
+        } catch (ParseException ex) {
+            Exceptions.printStackTrace(ex);
+        }
+        return ret.get();
+    }
+
+    private static class ItemFactoryImpl implements JavaCompletionTask.ItemFactory<Completion> {
+
+        private static final Set<String> SUPPORTED_ELEMENT_KINDS = new HashSet<>(Arrays.asList("PACKAGE", "CLASS", "INTERFACE", "ENUM", "ANNOTATION_TYPE", "METHOD", "CONSTRUCTOR", "INSTANCE_INIT", "STATIC_INIT", "FIELD", "ENUM_CONSTANT", "TYPE_PARAMETER", "MODULE"));
+        private static final int DEPRECATED = 10;
+        private final Document doc;
+        private final int offset;
+        private final CompilationInfo info;
+        private final Scope scope;
+
+        public ItemFactoryImpl(CompilationInfo info, int offset) throws IOException {
+            this.offset = offset;
+            this.info = info;
+            this.doc = info.getDocument();
+            this.scope = info.getTrees().getScope(info.getTreeUtilities().pathFor(offset));
+        }
+
+        @Override
+        public Completion createKeywordItem(String kwd, String postfix, int substitutionOffset, boolean smartType) {
+            return CompletionCollector.newBuilder(kwd)
+                    .kind(Completion.Kind.Keyword)
+                    .sortText(String.format("%4d%s", smartType ? 670 : 1670, kwd))
+                    .insertText(kwd + postfix)
+                    .build();
+        }
+
+        @Override
+        public Completion createPackageItem(String pkgFQN, int substitutionOffset, boolean inPackageStatement) {
+            final String simpleName = pkgFQN.substring(pkgFQN.lastIndexOf('.') + 1);
+            return CompletionCollector.newBuilder(simpleName)
+                    .kind(Completion.Kind.Folder)
+                    .sortText(String.format("%4d%s#%s", 1900, simpleName, pkgFQN))
+                    .insertText(simpleName + (inPackageStatement ? "" : "."))
+                    .build();
+        }
+
+        @Override
+        public Completion createTypeItem(CompilationInfo info, TypeElement elem, DeclaredType type, int substitutionOffset, ReferencesCount referencesCount, boolean isDeprecated, boolean insideNew, boolean addTypeVars, boolean addSimpleName, boolean smartType, boolean autoImportEnclosingType) {
+            String name = elem.getQualifiedName().toString();
+            int idx = name.lastIndexOf('.');
+            String pkgName = idx < 0 ? "" : name.substring(0, idx);
+            CompletionCollector.Builder builder = CompletionCollector.newBuilder(elem.getSimpleName().toString())
+                    .kind(elementKind2CompletionItemKind(elem.getKind()))
+                    .sortText(String.format("%4d%s#%2d#%s", smartType ? 800 : 1800, elem.getSimpleName().toString(), Utilities.getImportanceLevel(name), pkgName))
+                    .detail(name);
+            ElementHandle<TypeElement> handle = SUPPORTED_ELEMENT_KINDS.contains(elem.getKind().name()) ? ElementHandle.create(elem) : null;
+            if (handle != null) {
+                builder.documentation(getDocumentation(doc, handle))
+                        .additionalTextEdits(addImport(doc, handle));
+            }
+            if (isDeprecated) {
+                builder.addTag(Completion.Tag.Deprecated);
+            }
+            return builder.build();
+        }
+
+        @Override
+        public Completion createTypeItem(ElementHandle<TypeElement> handle, EnumSet<ElementKind> kinds, int substitutionOffset, ReferencesCount referencesCount, Source source, boolean insideNew, boolean addTypeVars, boolean afterExtends) {
+            TypeElement te = handle.resolve(info);
+            if (te != null && info.getTrees().isAccessible(scope, te)) {
+                String name = handle.getQualifiedName();
+                int idx = name.lastIndexOf('.');
+                String pkgName = idx < 0 ? "" : name.substring(0, idx);
+                return CompletionCollector.newBuilder(te.getSimpleName().toString())
+                        .kind(elementKind2CompletionItemKind(handle.getKind()))
+                        .sortText(String.format("%4d%s#%2d#%s", 1800, te.getSimpleName().toString(), Utilities.getImportanceLevel(name), pkgName))
+                        .detail(name)
+                        .documentation(getDocumentation(doc, handle))
+                        .additionalTextEdits(addImport(doc, handle))
+                        .build();
+            }
+            return null;
+        }
+
+        @Override
+        public Completion createArrayItem(CompilationInfo info, ArrayType type, int substitutionOffset, ReferencesCount referencesCount, Elements elements) {
+            return null; //TODO: fill
+        }
+
+        @Override
+        public Completion createTypeParameterItem(TypeParameterElement elem, int substitutionOffset) {
+            return CompletionCollector.newBuilder(elem.getSimpleName().toString())
+                    .kind(elementKind2CompletionItemKind(elem.getKind()))
+                    .sortText(String.format("%4d%s", 1700, elem.getSimpleName().toString()))
+                    .build();
+        }
+
+        @Override
+        public Completion createVariableItem(CompilationInfo info, VariableElement elem, TypeMirror type, int substitutionOffset, ReferencesCount referencesCount, boolean isInherited, boolean isDeprecated, boolean smartType, int assignToVarOffset) {
+            int priority = elem.getKind() == ElementKind.ENUM_CONSTANT || elem.getKind() == ElementKind.FIELD ? smartType ? 300 : 1300 : smartType ? 200 : 1200;
+            CompletionCollector.Builder builder = CompletionCollector.newBuilder(elem.getSimpleName().toString())
+                    .kind(elementKind2CompletionItemKind(elem.getKind()))
+                    .sortText(String.format("%4d%s", priority, elem.getSimpleName().toString()));
+            ElementHandle<VariableElement> handle = SUPPORTED_ELEMENT_KINDS.contains(elem.getKind().name()) ? ElementHandle.create(elem) : null;
+            if (handle != null) {
+                builder.documentation(getDocumentation(doc, handle));
+            }
+            if (isDeprecated) {
+                builder.addTag(Completion.Tag.Deprecated);
+            }
+            return builder.build();
+        }
+
+        @Override
+        public Completion createVariableItem(CompilationInfo info, String varName, int substitutionOffset, boolean newVarName, boolean smartType) {
+            return CompletionCollector.newBuilder(varName)
+                    .kind(Completion.Kind.Variable)
+                    .sortText(String.format("%4d%s", smartType ? 200 : 1200, varName))
+                    .build();
+        }
+
+        @Override
+        public Completion createExecutableItem(CompilationInfo info, ExecutableElement elem, ExecutableType type, int substitutionOffset, ReferencesCount referencesCount, boolean isInherited, boolean isDeprecated, boolean inImport, boolean addSemicolon, boolean smartType, int assignToVarOffset, boolean memberRef) {
+            Iterator<? extends VariableElement> it = elem.getParameters().iterator();
+            Iterator<? extends TypeMirror> tIt = type.getParameterTypes().iterator();
+            StringBuilder label = new StringBuilder();
+            String sep = "";
+            label.append(elem.getSimpleName());
+            label.append("(");
+            StringBuilder sortParams = new StringBuilder();
+            sortParams.append('(');
+            int cnt = 0;
+            while(it.hasNext() && tIt.hasNext()) {
+                TypeMirror tm = tIt.next();
+                if (tm == null) {
+                    break;
+                }
+                label.append(sep);
+                String paramTypeName = Utilities.getTypeName(info, tm, false, elem.isVarArgs() && !tIt.hasNext()).toString();
+                label.append(paramTypeName);
+                label.append(' ');
+                label.append(it.next().getSimpleName());
+                sep = ", ";
+                sortParams.append(paramTypeName);
+                if (tIt.hasNext()) {
+                    sortParams.append(',');
+                }
+                cnt++;
+            }
+            label.append(") : ");
+            sortParams.append(')');
+            TypeMirror retType = type.getReturnType();
+            label.append(Utilities.getTypeName(info, retType, false).toString());
+            StringBuilder insertText = new StringBuilder();
+            insertText.append(elem.getSimpleName());
+            insertText.append("(");
+            if (elem.getParameters().isEmpty()) {
+                insertText.append(")");
+            }
+            int priority = elem.getKind() == ElementKind.METHOD ? smartType ? 500 : 1500 : smartType ? 650 : 1650;
+            CompletionCollector.Builder builder = CompletionCollector.newBuilder(label.toString())
+                    .kind(elementKind2CompletionItemKind(elem.getKind()))
+                    .insertText(insertText.toString())
+                    .sortText(String.format("%4d%s#%2d%s", priority, elem.getSimpleName().toString(), cnt, sortParams));
+            ElementHandle<ExecutableElement> handle = SUPPORTED_ELEMENT_KINDS.contains(elem.getKind().name()) ? ElementHandle.create(elem) : null;
+            if (handle != null) {
+                builder.documentation(getDocumentation(doc, handle));
+            }
+            if (isDeprecated) {
+                builder.addTag(Completion.Tag.Deprecated);
+            }
+            return builder.build();
+        }
+
+        @Override
+        public Completion createThisOrSuperConstructorItem(CompilationInfo info, ExecutableElement elem, ExecutableType type, int substitutionOffset, boolean isDeprecated, String name) {
+            Completion item = createExecutableItem(info, elem, type, substitutionOffset, null, false, isDeprecated, false, false, false, -1, false);
+            String simpleName = name != null ? name : elem.getEnclosingElement().getSimpleName().toString();
+            int idx = item.getLabel().indexOf('(');
+            String label = simpleName + item.getLabel().substring(idx);
+            idx = item.getInsertText().indexOf('(');
+            String insertText = simpleName + item.getInsertText().substring(idx);
+            CompletionCollector.Builder builder = CompletionCollector.newBuilder(label)
+                    .kind(Completion.Kind.Constructor)
+                    .insertText(insertText)
+                    .sortText(String.format("%4d%s", name != null ? 1550 : 1650, item.getSortText().substring(4)));
+            ElementHandle<ExecutableElement> handle = SUPPORTED_ELEMENT_KINDS.contains(elem.getKind().name()) ? ElementHandle.create(elem) : null;
+            if (handle != null) {
+                builder.documentation(getDocumentation(doc, handle));
+            }
+            return builder.build();
+        }
+
+        @Override
+        public Completion createOverrideMethodItem(CompilationInfo info, ExecutableElement elem, ExecutableType type, int substitutionOffset, boolean implement) {
+            Completion item = createExecutableItem(info, elem, type, substitutionOffset, null, false, false, false, false, false, -1, false);
+            CompletionCollector.Builder builder = CompletionCollector.newBuilder(String.format("%s - %s", item.getLabel(), implement ? "implement" : "override"))
+                    .kind(elementKind2CompletionItemKind(elem.getKind()));
+            ElementHandle<ExecutableElement> handle = SUPPORTED_ELEMENT_KINDS.contains(elem.getKind().name()) ? ElementHandle.create(elem) : null;
+            if (handle != null) {
+                builder.documentation(getDocumentation(doc, handle));
+            }
+            try {
+                List<TextEdit> textEdits = modify2TextEdits(JavaSource.forFileObject(info.getFileObject()), wc -> {
+                    wc.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED);
+                    TreePath tp = wc.getTreeUtilities().pathFor(offset);
+                    if (implement) {
+                        GeneratorUtils.generateAbstractMethodImplementation(wc, tp, elem, offset);
+                    } else {
+                        GeneratorUtils.generateMethodOverride(wc, tp, elem, offset);
+                    }
+                });
+                if (!textEdits.isEmpty()) {
+                    builder.textEdit(textEdits.get(0));
+                }
+            } catch (IOException ex) {
+            }
+            return builder.build();
+        }
+
+        @Override
+        public Completion createGetterSetterMethodItem(CompilationInfo info, VariableElement elem, TypeMirror type, int substitutionOffset, String name, boolean setter) {
+            return null; //TODO: fill
+        }
+
+        @Override
+        public Completion createDefaultConstructorItem(TypeElement elem, int substitutionOffset, boolean smartType) {
+            return null; //TODO: fill
+        }
+
+        @Override
+        public Completion createParametersItem(CompilationInfo info, ExecutableElement elem, ExecutableType type, int substitutionOffset, boolean isDeprecated, int activeParamIndex, String name) {
+            return null; //TODO: fill
+        }
+
+        @Override
+        public Completion createAnnotationItem(CompilationInfo info, TypeElement elem, DeclaredType type, int substitutionOffset, ReferencesCount referencesCount, boolean isDeprecated) {
+            return null; //TODO: fill
+        }
+
+        @Override
+        public Completion createAttributeItem(CompilationInfo info, ExecutableElement elem, ExecutableType type, int substitutionOffset, boolean isDeprecated) {
+            StringBuilder insertText = new StringBuilder();
+            insertText.append(elem.getSimpleName());
+            insertText.append("=");
+            CompletionCollector.Builder builder = CompletionCollector.newBuilder(elem.getSimpleName().toString())
+                    .kind(Completion.Kind.Property)
+                    .insertText(insertText.toString())
+                    .insertTextFormat(Completion.TextFormat.PlainText)
+                    .sortText(String.format("%4d%s", isDeprecated ? 100 + DEPRECATED : 100, elem.getSimpleName().toString()));
+            ElementHandle<ExecutableElement> handle = SUPPORTED_ELEMENT_KINDS.contains(elem.getKind().name()) ? ElementHandle.create(elem) : null;
+            if (handle != null) {
+                builder.documentation(getDocumentation(doc, handle));
+            }
+            if (isDeprecated) {
+                builder.addTag(Completion.Tag.Deprecated);
+            }
+            return builder.build();
+        }
+
+        @Override
+        public Completion createAttributeValueItem(CompilationInfo info, String value, String documentation, TypeElement element, int substitutionOffset, ReferencesCount referencesCount) {
+            return CompletionCollector.newBuilder(value)
+                    .kind(Completion.Kind.Text)
+                    .sortText(value)
+                    .documentation(documentation)
+                    .build();
+        }
+
+        private static final Object KEY_IMPORT_TEXT_EDITS = new Object();
+
+        @Override
+        public Completion createStaticMemberItem(CompilationInfo info, DeclaredType type, Element memberElem, TypeMirror memberType, boolean multipleVersions, int substitutionOffset, boolean isDeprecated, boolean addSemicolon) {
+            //TODO: prefer static imports (but would be much slower?)
+            //TODO: should be resolveImport instead of addImports:
+            Map<Element, List<TextEdit>> imports = (Map<Element, List<TextEdit>>) info.getCachedValue(KEY_IMPORT_TEXT_EDITS);
+            if (imports == null) {
+                info.putCachedValue(KEY_IMPORT_TEXT_EDITS, imports = new HashMap<>(), CompilationInfo.CacheClearPolicy.ON_TASK_END);
+            }
+            List<TextEdit> currentClassImport = imports.computeIfAbsent(type.asElement(), toImport -> {
+                try {
+                    return modify2TextEdits(JavaSource.forFileObject(info.getFileObject()), wc -> {
+                        wc.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED);
+                        wc.rewrite(info.getCompilationUnit(), GeneratorUtilities.get(wc).addImports(wc.getCompilationUnit(), new HashSet<>(Arrays.asList(toImport))));
+                    });
+                } catch (IOException ex) {
+                    return Collections.emptyList();
+                }
+            });
+            String label = type.asElement().getSimpleName() + "." + memberElem.getSimpleName();
+            String sortText = memberElem.getSimpleName().toString();
+            if (memberElem.getKind().isField()) {
+                sortText += String.format("#%s", Utilities.getTypeName(info, type, false)); //NOI18N
+            } else {
+                StringBuilder sortParams = new StringBuilder();
+                sortParams.append('(');
+                int cnt = 0;
+                Iterator<? extends TypeMirror> tIt = ((ExecutableType)memberType).getParameterTypes().iterator();
+                while(tIt.hasNext()) {
+                    TypeMirror tm = tIt.next();
+                    if (tm == null) {
+                        break;
+                    }
+                    sortParams.append(Utilities.getTypeName(info, tm, false, ((ExecutableElement)memberElem).isVarArgs() && !tIt.hasNext()).toString());
+                    if (tIt.hasNext()) {
+                        sortParams.append(',');
+                    }
+                    cnt++;
+                }
+                sortParams.append(')');
+                sortText += String.format("#%2d#%s#s", cnt, sortParams.toString(), Utilities.getTypeName(info, type, false)); //NOI18N
+            }
+            CompletionCollector.Builder builder = CompletionCollector.newBuilder(label)
+                    .kind(elementKind2CompletionItemKind(memberElem.getKind()))
+                    .insertText(label)
+                    .additionalTextEdits(currentClassImport)
+                    .sortText(String.format("%4d%s", memberElem.getKind().isField() ? 720 : 750, sortText));
+            ElementHandle<Element> handle = SUPPORTED_ELEMENT_KINDS.contains(memberElem.getKind().name()) ? ElementHandle.create(memberElem) : null;
+            if (handle != null) {
+                builder.documentation(getDocumentation(doc, handle));
+            }
+            if (isDeprecated) {
+                builder.addTag(Completion.Tag.Deprecated);
+            }
+            return builder.build();
+        }
+
+        @Override
+        public Completion createStaticMemberItem(ElementHandle<TypeElement> handle, String name, int substitutionOffset, boolean addSemicolon, ReferencesCount referencesCount, Source source) {
+            return null; //TODO: fill
+        }
+
+        @Override
+        public Completion createChainedMembersItem(CompilationInfo info, List<? extends Element> chainedElems, List<? extends TypeMirror> chainedTypes, int substitutionOffset, boolean isDeprecated, boolean addSemicolon) {
+            return null; //TODO: fill
+        }
+
+        @Override
+        public Completion createInitializeAllConstructorItem(CompilationInfo info, boolean isDefault, Iterable<? extends VariableElement> fields, ExecutableElement superConstructor, TypeElement parent, int substitutionOffset) {
+            return null; //TODO: fill
+        }
+
+        private static Supplier<String> getDocumentation(Document doc, ElementHandle<?> handle) {
+            return () -> {
+                try {
+                    String[] ret = new String[1];
+                    ParserManager.parse(Collections.singletonList(Source.create(doc)), new UserTask() {
+                        public void run (ResultIterator resultIterator) throws Exception {
+                            CompilationInfo info = CompilationInfo.get(resultIterator.getParserResult());
+                            if (info != null) {
+                                Element element = handle.resolve(info);
+                                if (element != null) {
+                                    ret[0] = ElementJavadoc.create(info, element, null).getText();
+                                }
+                            }
+                        }
+                    });
+                    return ret[0];
+                } catch (ParseException ex) {
+                    throw new RuntimeException(ex);
+                }
+            };
+        }
+
+        private static Supplier<List<TextEdit>> addImport(Document doc, ElementHandle<?> handle) {
+            return () -> {
+                try {
+                    return modify2TextEdits(JavaSource.forDocument(doc), copy -> {
+                        copy.toPhase(JavaSource.Phase.RESOLVED);
+                        Element e = handle.resolve(copy);
+                        if (e != null) {
+                            copy.rewrite(copy.getCompilationUnit(), GeneratorUtilities.get(copy).addImports(copy.getCompilationUnit(), Collections.singleton(e)));
+                        }
+                    });
+                } catch (IOException ex) {
+                    throw new RuntimeException(ex);
+                }
+            };
+        }
+
+        private static Completion.Kind elementKind2CompletionItemKind(ElementKind kind) {
+            switch (kind) {
+                case PACKAGE:
+                    return Completion.Kind.Folder;
+                case ENUM:
+                    return Completion.Kind.Enum;
+                case CLASS:
+                    return Completion.Kind.Class;
+                case ANNOTATION_TYPE:
+                    return Completion.Kind.Interface;
+                case INTERFACE:
+                    return Completion.Kind.Interface;
+                case ENUM_CONSTANT:
+                    return Completion.Kind.EnumMember;
+                case FIELD:
+                    return Completion.Kind.Field;
+                case PARAMETER:
+                    return Completion.Kind.Variable;
+                case LOCAL_VARIABLE:
+                    return Completion.Kind.Variable;
+                case EXCEPTION_PARAMETER:
+                    return Completion.Kind.Variable;
+                case METHOD:
+                    return Completion.Kind.Method;
+                case CONSTRUCTOR:
+                    return Completion.Kind.Constructor;
+                case TYPE_PARAMETER:
+                    return Completion.Kind.TypeParameter;
+                case RESOURCE_VARIABLE:
+                    return Completion.Kind.Variable;
+                case MODULE:
+                    return Completion.Kind.Module;
+                case STATIC_INIT:
+                case INSTANCE_INIT:
+                case OTHER:
+                default:
+                    return Completion.Kind.Text;
+            }
+        }
+
+        private static List<TextEdit> modify2TextEdits(JavaSource js, Task<WorkingCopy> task) throws IOException {
+            FileObject[] file = new FileObject[1];
+            ModificationResult changes = js.runModificationTask(wc -> {
+                task.run(wc);
+                file[0] = wc.getFileObject();
+            });
+            List<? extends ModificationResult.Difference> diffs = changes.getDifferences(file[0]);
+            if (diffs == null) {
+                return Collections.emptyList();
+            }
+            return diffs.stream().map(diff -> {
+                String newText = diff.getNewText();
+                return new TextEdit(diff.getStartPosition().getOffset(), diff.getEndPosition().getOffset(), newText != null ? newText : "");
+            }).collect(Collectors.toList());
+        }
+    }
+}
diff --git a/java/java.editor/src/org/netbeans/modules/java/editor/hyperlink/JavaHyperlinkProvider.java b/java/java.editor/src/org/netbeans/modules/java/editor/hyperlink/JavaHyperlinkProvider.java
index ed69d9e..74030ee 100644
--- a/java/java.editor/src/org/netbeans/modules/java/editor/hyperlink/JavaHyperlinkProvider.java
+++ b/java/java.editor/src/org/netbeans/modules/java/editor/hyperlink/JavaHyperlinkProvider.java
@@ -21,13 +21,17 @@ package org.netbeans.modules.java.editor.hyperlink;
 
 import java.util.EnumSet;
 import java.util.Set;
+import java.util.concurrent.CompletableFuture;
 import javax.swing.text.Document;
 import javax.swing.text.JTextComponent;
 import org.netbeans.api.editor.EditorRegistry;
+import org.netbeans.api.editor.mimelookup.MimeRegistration;
+import org.netbeans.api.lsp.HyperlinkLocation;
 import org.netbeans.lib.editor.hyperlink.spi.HyperlinkProviderExt;
 import org.netbeans.lib.editor.hyperlink.spi.HyperlinkType;
 import org.netbeans.modules.editor.java.GoToSupport;
 import org.netbeans.modules.java.editor.overridden.GoToImplementation;
+import org.netbeans.spi.lsp.HyperlinkLocationProvider;
 
 /**
  * Implementation of the hyperlink provider for java language.
@@ -39,22 +43,26 @@ import org.netbeans.modules.java.editor.overridden.GoToImplementation;
  * @author Jan Lahoda
  */
 public final class JavaHyperlinkProvider implements HyperlinkProviderExt {
- 
+
     public JavaHyperlinkProvider() {
     }
 
+    @Override
     public Set<HyperlinkType> getSupportedHyperlinkTypes() {
         return EnumSet.of(HyperlinkType.GO_TO_DECLARATION, HyperlinkType.ALT_HYPERLINK);
     }
 
+    @Override
     public boolean isHyperlinkPoint(Document doc, int offset, HyperlinkType type) {
         return getHyperlinkSpan(doc, offset, type) != null;
     }
 
+    @Override
     public int[] getHyperlinkSpan(Document doc, int offset, HyperlinkType type) {
         return GoToSupport.getIdentifierOrLambdaArrowSpan(doc, offset, null);
     }
 
+    @Override
     public void performClickAction(Document doc, int offset, HyperlinkType type) {
         switch (type) {
             case GO_TO_DECLARATION:
@@ -62,7 +70,6 @@ public final class JavaHyperlinkProvider implements HyperlinkProviderExt {
                 break;
             case ALT_HYPERLINK:
                 JTextComponent focused = EditorRegistry.focusedComponent();
-                
                 if (focused != null && focused.getDocument() == doc) {
                     focused.setCaretPosition(offset);
                     GoToImplementation.goToImplementation(focused);
@@ -71,8 +78,17 @@ public final class JavaHyperlinkProvider implements HyperlinkProviderExt {
         }
     }
 
+    @Override
     public String getTooltipText(Document doc, int offset, HyperlinkType type) {
         return GoToSupport.getGoToElementTooltip(doc, offset, false, type);
     }
 
+    @MimeRegistration(mimeType = "text/x-java", service = HyperlinkLocationProvider.class)
+    public static class LocationProvider implements HyperlinkLocationProvider {
+
+        @Override
+        public CompletableFuture<HyperlinkLocation> getHyperlinkLocation(Document doc, int offset) {
+            return GoToSupport.getGoToLocation(doc, offset);
+        }
+    }
 }
diff --git a/java/java.lsp.server/nbcode/nbproject/platform.properties b/java/java.lsp.server/nbcode/nbproject/platform.properties
index 2723dce..ea16447 100644
--- a/java/java.lsp.server/nbcode/nbproject/platform.properties
+++ b/java/java.lsp.server/nbcode/nbproject/platform.properties
@@ -17,6 +17,7 @@
 
 branding.token=nbcode
 cluster.path=\
+    ${nbplatform.active.dir}/enterprise:\
     ${nbplatform.active.dir}/extide:\
     ${nbplatform.active.dir}/ide:\
     ${nbplatform.active.dir}/java:\
@@ -71,7 +72,6 @@ disabled.modules=\
     org.netbeans.lib.nbjshell,\
     org.netbeans.lib.nbjshell9,\
     org.netbeans.lib.terminalemulator,\
-    org.netbeans.libs.bytelist,\
     org.netbeans.libs.cglib,\
     org.netbeans.libs.commons_net,\
     org.netbeans.libs.git,\
@@ -82,7 +82,6 @@ disabled.modules=\
     org.netbeans.libs.jshell.compile,\
     org.netbeans.libs.jsr223,\
     org.netbeans.libs.jstestdriver,\
-    org.netbeans.libs.jvyamlb,\
     org.netbeans.libs.nbi.ant,\
     org.netbeans.libs.nbi.engine,\
     org.netbeans.libs.plist,\
@@ -248,7 +247,6 @@ disabled.modules=\
     org.netbeans.modules.languages.diff,\
     org.netbeans.modules.languages.ini,\
     org.netbeans.modules.languages.manifest,\
-    org.netbeans.modules.languages.yaml,\
     org.netbeans.modules.localhistory,\
     org.netbeans.modules.localtasks,\
     org.netbeans.modules.lsp.client,\
@@ -351,7 +349,114 @@ disabled.modules=\
     org.openide.execution.compat8,\
     org.openide.options,\
     org.openide.util.enumerations,\
-    org.openidex.util
+    org.openidex.util,\
+    org.netbeans.api.web.webmodule,\
+    org.netbeans.libs.amazon,\
+    org.netbeans.libs.commons_fileupload,\
+    org.netbeans.libs.elimpl,\
+    org.netbeans.libs.glassfish_logging,\
+    org.netbeans.libs.jstl,\
+    org.netbeans.modules.cloud.amazon,\
+    org.netbeans.modules.cloud.common,\
+    org.netbeans.modules.el.lexer,\
+    org.netbeans.modules.glassfish.common,\
+    org.netbeans.modules.glassfish.eecommon,\
+    org.netbeans.modules.glassfish.javaee,\
+    org.netbeans.modules.glassfish.tooling,\
+    org.netbeans.modules.gradle.javaee,\
+    org.netbeans.modules.j2ee.ant,\
+    org.netbeans.modules.j2ee.api.ejbmodule,\
+    org.netbeans.modules.j2eeapis,\
+    org.netbeans.modules.j2ee.clientproject,\
+    org.netbeans.modules.j2ee.common,\
+    org.netbeans.modules.j2ee.core,\
+    org.netbeans.modules.j2ee.dd,\
+    org.netbeans.modules.j2ee.ddloaders,\
+    org.netbeans.modules.j2ee.dd.webservice,\
+    org.netbeans.modules.j2ee.earproject,\
+    org.netbeans.modules.j2ee.ejbcore,\
+    org.netbeans.modules.j2ee.ejbjarproject,\
+    org.netbeans.modules.j2ee.ejbrefactoring,\
+    org.netbeans.modules.j2ee.ejbverification,\
+    org.netbeans.modules.j2ee.genericserver,\
+    org.netbeans.modules.j2ee.kit,\
+    org.netbeans.modules.j2ee.platform,\
+    org.netbeans.modules.j2eeserver,\
+    org.netbeans.modules.j2ee.sun.appsrv,\
+    org.netbeans.modules.j2ee.sun.dd,\
+    org.netbeans.modules.j2ee.sun.ddui,\
+    org.netbeans.modules.jakartaee8.api,\
+    org.netbeans.modules.jakartaee8.platform,\
+    org.netbeans.modules.javaee7.api,\
+    org.netbeans.modules.javaee8.api,\
+    org.netbeans.modules.javaee.api,\
+    org.netbeans.modules.javaee.beanvalidation,\
+    org.netbeans.modules.javaee.project,\
+    org.netbeans.modules.javaee.resources,\
+    org.netbeans.modules.javaee.specs.support,\
+    org.netbeans.modules.javaee.wildfly,\
+    org.netbeans.modules.jellytools.enterprise,\
+    org.netbeans.modules.jsp.lexer,\
+    org.netbeans.modules.maven.j2ee,\
+    org.netbeans.modules.maven.jaxws,\
+    org.netbeans.modules.payara.common,\
+    org.netbeans.modules.payara.eecommon,\
+    org.netbeans.modules.payara.jakartaee,\
+    org.netbeans.modules.payara.micro,\
+    org.netbeans.modules.payara.tooling,\
+    org.netbeans.modules.profiler.j2ee,\
+    org.netbeans.modules.projectimport.eclipse.web,\
+    org.netbeans.modules.servletjspapi,\
+    org.netbeans.modules.spring.webmvc,\
+    org.netbeans.modules.tomcat5,\
+    org.netbeans.modules.web.beans,\
+    org.netbeans.modules.web.bootsfaces,\
+    org.netbeans.modules.web.client.rest,\
+    org.netbeans.modules.web.core,\
+    org.netbeans.modules.web.core.syntax,\
+    org.netbeans.modules.web.debug,\
+    org.netbeans.modules.web.el,\
+    org.netbeans.modules.web.freeform,\
+    org.netbeans.modules.web.jsf12,\
+    org.netbeans.modules.web.jsf12ri,\
+    org.netbeans.modules.web.jsf20,\
+    org.netbeans.modules.web.jsfapi,\
+    org.netbeans.modules.web.jsf.editor,\
+    org.netbeans.modules.web.jsf.icefaces,\
+    org.netbeans.modules.web.jsf,\
+    org.netbeans.modules.web.jsf.kit,\
+    org.netbeans.modules.web.jsf.navigation,\
+    org.netbeans.modules.web.jsf.richfaces,\
+    org.netbeans.modules.web.jspparser,\
+    org.netbeans.modules.web.kit,\
+    org.netbeans.modules.weblogic.common,\
+    org.netbeans.modules.web.monitor,\
+    org.netbeans.modules.web.primefaces,\
+    org.netbeans.modules.web.project,\
+    org.netbeans.modules.web.refactoring,\
+    org.netbeans.modules.websocket,\
+    org.netbeans.modules.web.struts,\
+    org.netbeans.modules.websvc.clientapi,\
+    org.netbeans.modules.websvc.core,\
+    org.netbeans.modules.websvc.customization,\
+    org.netbeans.modules.websvc.design,\
+    org.netbeans.modules.websvc.editor.hints,\
+    org.netbeans.modules.websvc.jaxwsapi,\
+    org.netbeans.modules.websvc.jaxws.lightapi,\
+    org.netbeans.modules.websvc.jaxwsmodel,\
+    org.netbeans.modules.websvc.kit,\
+    org.netbeans.modules.websvc.manager,\
+    org.netbeans.modules.websvc.metro.lib,\
+    org.netbeans.modules.websvc.owsm,\
+    org.netbeans.modules.websvc.projectapi,\
+    org.netbeans.modules.websvc.restapi,\
+    org.netbeans.modules.websvc.rest,\
+    org.netbeans.modules.websvc.restkit,\
+    org.netbeans.modules.websvc.restlib,\
+    org.netbeans.modules.websvc.saas.codegen.j2ee,\
+    org.netbeans.modules.websvc.utilities,\
+    org.netbeans.modules.websvc.websvcapi,\
+    org.netbeans.modules.websvc.wsstackapi
 nbplatform.active=nball
 suite.dir=${basedir}
 nbplatform.nball.netbeans.dest.dir=${suite.dir}/../../../nbbuild/netbeans
diff --git a/java/java.lsp.server/nbproject/project.xml b/java/java.lsp.server/nbproject/project.xml
index 048173d..d78ddd8 100644
--- a/java/java.lsp.server/nbproject/project.xml
+++ b/java/java.lsp.server/nbproject/project.xml
@@ -87,6 +87,15 @@
                     </run-dependency>
                 </dependency>
                 <dependency>
+                    <code-name-base>org.netbeans.api.lsp</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <specification-version>1.0</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
                     <code-name-base>org.netbeans.api.progress</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
@@ -174,29 +183,29 @@
                     </run-dependency>
                 </dependency>
                 <dependency>
-                    <code-name-base>org.netbeans.modules.gsf.testrunner</code-name-base>
+                    <code-name-base>org.netbeans.modules.extexecution.base</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
                         <release-version>2</release-version>
-                        <specification-version>2.22</specification-version>
+                        <specification-version>1.17</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
-                    <code-name-base>org.netbeans.modules.gsf.testrunner.ui</code-name-base>
+                    <code-name-base>org.netbeans.modules.gsf.testrunner</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
-                        <specification-version>1.22</specification-version>
+                        <release-version>2</release-version>
+                        <specification-version>2.22</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
-                    <code-name-base>org.netbeans.modules.extexecution.base</code-name-base>
+                    <code-name-base>org.netbeans.modules.gsf.testrunner.ui</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
                     <run-dependency>
-                        <release-version>2</release-version>
-                        <specification-version>1.17</specification-version>
+                        <specification-version>1.22</specification-version>
                     </run-dependency>
                 </dependency>
                 <dependency>
diff --git a/java/java.lsp.server/script/etc/nbcode.clusters b/java/java.lsp.server/script/etc/nbcode.clusters
index 622f750..2151943 100644
--- a/java/java.lsp.server/script/etc/nbcode.clusters
+++ b/java/java.lsp.server/script/etc/nbcode.clusters
@@ -4,4 +4,5 @@ extide
 webcommon
 java
 extra
+enterprise
 nbcode
diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java
index db228e1..908c9d2 100644
--- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java
+++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java
@@ -24,7 +24,6 @@ import com.sun.source.tree.ClassTree;
 import com.sun.source.tree.CompilationUnitTree;
 import com.sun.source.tree.LineMap;
 import com.sun.source.tree.MethodTree;
-import com.sun.source.tree.Scope;
 import com.sun.source.tree.Tree;
 import com.sun.source.tree.Tree.Kind;
 import com.sun.source.tree.VariableTree;
@@ -40,7 +39,6 @@ import java.net.URI;
 import java.net.URL;
 import java.time.Instant;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
@@ -57,6 +55,7 @@ import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.BiConsumer;
 import java.util.function.IntFunction;
 import java.util.logging.Level;
@@ -67,13 +66,6 @@ import javax.lang.model.element.Element;
 import javax.lang.model.element.ElementKind;
 import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.TypeParameterElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.ArrayType;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.ExecutableType;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.Elements;
 import javax.swing.text.BadLocationException;
 import javax.swing.text.Document;
 import javax.swing.text.StyledDocument;
@@ -85,9 +77,9 @@ import org.eclipse.lsp4j.CodeLensParams;
 import org.eclipse.lsp4j.Command;
 import org.eclipse.lsp4j.CompletionItem;
 import org.eclipse.lsp4j.CompletionItemKind;
+import org.eclipse.lsp4j.CompletionItemTag;
 import org.eclipse.lsp4j.CompletionList;
 import org.eclipse.lsp4j.CompletionParams;
-import org.eclipse.lsp4j.CompletionTriggerKind;
 import org.eclipse.lsp4j.CreateFile;
 import org.eclipse.lsp4j.DefinitionParams;
 import org.eclipse.lsp4j.Diagnostic;
@@ -138,13 +130,10 @@ import org.eclipse.lsp4j.services.LanguageClient;
 import org.eclipse.lsp4j.services.LanguageClientAware;
 import org.eclipse.lsp4j.services.TextDocumentService;
 import org.netbeans.api.annotations.common.CheckForNull;
-import org.netbeans.api.java.classpath.ClassPath;
 import org.netbeans.api.java.lexer.JavaTokenId;
-import org.netbeans.api.java.queries.SourceJavadocAttacher;
-import org.netbeans.api.java.source.ClasspathInfo;
+import org.netbeans.api.java.project.JavaProjectConstants;
 import org.netbeans.api.java.source.CompilationController;
 import org.netbeans.api.java.source.CompilationInfo;
-import org.netbeans.api.java.source.CompilationInfo.CacheClearPolicy;
 import org.netbeans.api.java.source.ElementHandle;
 import org.netbeans.api.java.source.GeneratorUtilities;
 import org.netbeans.api.java.source.JavaSource;
@@ -155,16 +144,19 @@ import org.netbeans.api.java.source.Task;
 import org.netbeans.api.java.source.TreePathHandle;
 import org.netbeans.api.java.source.TreeUtilities;
 import org.netbeans.api.java.source.WorkingCopy;
-import org.netbeans.api.java.source.support.ReferencesCount;
 import org.netbeans.api.java.source.ui.ElementJavadoc;
+import org.netbeans.api.java.source.ui.ElementOpen;
 import org.netbeans.api.lexer.TokenSequence;
+import org.netbeans.api.lsp.Completion;
+import org.netbeans.api.lsp.HyperlinkLocation;
+import org.netbeans.api.project.Project;
+import org.netbeans.api.project.ProjectUtils;
+import org.netbeans.api.project.SourceGroup;
+import org.netbeans.api.project.Sources;
 import org.netbeans.modules.editor.java.GoToSupport;
 import org.netbeans.modules.editor.java.GoToSupport.Context;
 import org.netbeans.modules.editor.java.GoToSupport.GoToTarget;
-import org.netbeans.modules.editor.java.Utilities;
 import org.netbeans.modules.gsf.testrunner.ui.api.TestMethodController.TestMethod;
-import org.netbeans.modules.java.completion.JavaCompletionTask;
-import org.netbeans.modules.java.completion.JavaCompletionTask.Options;
 import org.netbeans.modules.java.completion.JavaDocumentationTask;
 import org.netbeans.modules.java.editor.base.fold.JavaElementFoldVisitor;
 import org.netbeans.modules.java.editor.base.fold.JavaElementFoldVisitor.FoldCreator;
@@ -188,8 +180,6 @@ import org.netbeans.modules.java.hints.spiimpl.options.HintsSettings;
 import org.netbeans.modules.java.lsp.server.LspServerState;
 import org.netbeans.modules.java.lsp.server.Utils;
 import org.netbeans.modules.java.lsp.server.debugging.utils.ErrorUtilities;
-import org.netbeans.modules.java.source.ElementHandleAccessor;
-import org.netbeans.modules.java.source.ui.ElementOpenAccessor;
 import org.netbeans.modules.java.testrunner.ui.spi.ComputeTestMethods;
 import org.netbeans.modules.parsing.api.ParserManager;
 import org.netbeans.modules.parsing.api.ResultIterator;
@@ -215,7 +205,6 @@ import org.netbeans.spi.editor.hints.ErrorDescription;
 import org.netbeans.spi.editor.hints.Fix;
 import org.netbeans.spi.editor.hints.LazyFixList;
 import org.netbeans.spi.editor.hints.Severity;
-import org.netbeans.spi.java.classpath.support.ClassPathSupport;
 import org.netbeans.spi.java.hints.JavaFix;
 import org.openide.cookies.EditorCookie;
 import org.openide.filesystems.FileObject;
@@ -285,8 +274,12 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli
         }
     }
 
+    private List<Completion> lastCompletions = null;
+
     @Override
     public CompletableFuture<Either<List<CompletionItem>, CompletionList>> completion(CompletionParams params) {
+        lastCompletions = new ArrayList<>();
+        AtomicInteger index = new AtomicInteger(0);
         final CompletionList completionList = new CompletionList();
         // shortcut: if the projects are not yet initialized, return empty:
         if (server.openedProjects().getNow(null) == null) {
@@ -301,62 +294,85 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli
             EditorCookie ec = file.getLookup().lookup(EditorCookie.class);
             Document doc = ec.openDocument();
             final int caret = Utils.getOffset(doc, params.getPosition());
-            ParserManager.parse(Collections.singletonList(Source.create(doc)), new UserTask() {
-                @Override
-                public void run(ResultIterator resultIterator) throws Exception {
-                    TokenSequence<JavaTokenId> ts = resultIterator.getSnapshot().getTokenHierarchy().tokenSequence(JavaTokenId.language());
-                    if (ts.move(caret) == 0 || !ts.moveNext()) {
-                        if (!ts.movePrevious()) {
-                            ts.moveNext();
-                        }
+            List<CompletionItem> items = new ArrayList<>();
+            Completion.Context context = params.getContext() != null
+                    ? new Completion.Context(Completion.TriggerKind.valueOf(params.getContext().getTriggerKind().name()),
+                            params.getContext().getTriggerCharacter() == null || params.getContext().getTriggerCharacter().isEmpty() ? null : params.getContext().getTriggerCharacter().charAt(0))
+                    : null;
+            boolean isComplete = Completion.collect(doc, caret, context, completion -> {
+                CompletionItem item = new CompletionItem(completion.getLabel());
+                if (completion.getKind() != null) {
+                    item.setKind(CompletionItemKind.valueOf(completion.getKind().name()));
+                }
+                if (completion.getTags() != null) {
+                    item.setTags(completion.getTags().stream().map(tag -> CompletionItemTag.valueOf(tag.name())).collect(Collectors.toList()));
+                }
+                if (completion.getDetail() != null && completion.getDetail().isDone()) {
+                    item.setDetail(completion.getDetail().getNow(null));
+                }
+                if (completion.getDocumentation() != null && completion.getDocumentation().isDone()) {
+                    String documentation = completion.getDocumentation().getNow(null);
+                    if (documentation != null) {
+                        MarkupContent markup = new MarkupContent();
+                        markup.setKind("markdown");
+                        markup.setValue(html2MD(documentation));
+                        item.setDocumentation(markup);
                     }
-                    int len = caret - ts.offset();
-                    boolean allCompletion = params.getContext() != null && params.getContext().getTriggerKind() == CompletionTriggerKind.TriggerForIncompleteCompletions
-                            || len > 0 && ts.token().length() >= len && ts.token().id() == JavaTokenId.IDENTIFIER;
-                    CompilationController controller = CompilationController.get(resultIterator.getParserResult(ts.offset()));
-                    controller.toPhase(JavaSource.Phase.RESOLVED);
-                    JavaCompletionTask<CompletionItem> task = JavaCompletionTask.create(caret, new ItemFactoryImpl(client, controller, uri, ts.offset()), allCompletion ? EnumSet.of(Options.ALL_COMPLETION) : EnumSet.noneOf(Options.class), () -> false);
-                    task.run(resultIterator);
-                    List<CompletionItem> results = task.getResults();
-                    if (results != null) {
-                        for (Iterator<CompletionItem> it = results.iterator(); it.hasNext();) {
-                            CompletionItem item = it.next();
-                            if (item == null) {
-                                it.remove();
-                            }
-                        }
-                        completionList.setItems(results);
+                }
+                if (completion.isPreselect()) {
+                    item.setPreselect(true);
+                }
+                item.setSortText(completion.getSortText());
+                item.setFilterText(completion.getFilterText());
+                item.setInsertText(completion.getInsertText());
+                if (completion.getInsertTextFormat() != null) {
+                    item.setInsertTextFormat(InsertTextFormat.valueOf(completion.getInsertTextFormat().name()));
+                }
+                org.netbeans.api.lsp.TextEdit edit = completion.getTextEdit();
+                if (edit != null) {
+                    item.setTextEdit(new TextEdit(new Range(Utils.createPosition(file, edit.getStartOffset()), Utils.createPosition(file, edit.getEndOffset())), edit.getNewText()));
+                }
+                if (completion.getAdditionalTextEdits() != null && completion.getAdditionalTextEdits().isDone()) {
+                    List<org.netbeans.api.lsp.TextEdit> additionalTextEdits = completion.getAdditionalTextEdits().getNow(null);
+                    if (additionalTextEdits != null) {
+                        item.setAdditionalTextEdits(additionalTextEdits.stream().map(ed -> {
+                            return new TextEdit(new Range(Utils.createPosition(file, ed.getStartOffset()), Utils.createPosition(file, ed.getEndOffset())), ed.getNewText());
+                        }).collect(Collectors.toList()));
                     }
-                    completionList.setIsIncomplete(task.hasAdditionalClasses());
                 }
+                if (completion.getCommitCharacters() != null) {
+                    item.setCommitCharacters(completion.getCommitCharacters().stream().map(ch -> ch.toString()).collect(Collectors.toList()));
+                }
+                lastCompletions.add(completion);
+                item.setData(new CompletionData(uri, index.getAndIncrement()));
+                items.add(item);
             });
+            if (!isComplete) {
+                completionList.setIsIncomplete(true);
+            }
+            completionList.setItems(items);
             return CompletableFuture.completedFuture(Either.<List<CompletionItem>, CompletionList>forRight(completionList));
-        } catch (IOException | ParseException ex) {
+        } catch (IOException ex) {
             throw new IllegalStateException(ex);
         }
     }
 
     public static final class CompletionData {
         public String uri;
-        public int offset;
-        public String kind;
-        public String[] elementHandle;
+        public int index;
 
         public CompletionData() {
         }
 
-        public CompletionData(String uri, int offset, String kind, String[] elementHandle) {
+        public CompletionData(String uri, int index) {
             this.uri = uri;
-            this.offset = offset;
-            this.kind = kind;
-            this.elementHandle = elementHandle;
+            this.index = index;
         }
 
         @Override
         public String toString() {
-            return "CompletionData{" + "uri=" + uri + ", kind=" + kind + ", elementHandle=" + elementHandle + '}';
+            return "CompletionData{" + "uri=" + uri + ", index=" + index + '}';
         }
-        
     }
 
     @Override
@@ -364,438 +380,55 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli
         this.client = (NbCodeLanguageClient)client;
     }
 
-    private static class ItemFactoryImpl implements JavaCompletionTask.ItemFactory<CompletionItem> {
-
-        private static final int DEPRECATED = 10;
-        private final LanguageClient client;
-        private final String uri;
-        private final int offset;
-        private final CompilationInfo info;
-        private final Scope scope;
-
-        public ItemFactoryImpl(LanguageClient client, CompilationInfo info, String uri, int offset) {
-            this.client = client;
-            this.uri = uri;
-            this.offset = offset;
-            this.info = info;
-            this.scope = info.getTrees().getScope(info.getTreeUtilities().pathFor(offset));
-        }
-
-        private static final Set<String> SUPPORTED_ELEMENT_KINDS = new HashSet<>(Arrays.asList("PACKAGE", "CLASS", "INTERFACE", "ENUM", "ANNOTATION_TYPE", "METHOD", "CONSTRUCTOR", "INSTANCE_INIT", "STATIC_INIT", "FIELD", "ENUM_CONSTANT", "TYPE_PARAMETER", "MODULE"));
-
-        private void setCompletionData(CompletionItem ci, Element el) {
-            if (SUPPORTED_ELEMENT_KINDS.contains(el.getKind().name())) {
-                setCompletionData(ci, ElementHandle.create(el));
-            }
-        }
-
-        private void setCompletionData(CompletionItem ci, ElementHandle handle) {
-            ci.setData(new CompletionData(uri, offset, handle.getKind().name(), SourceUtils.getJVMSignature(handle)));
-        }
-
-        @Override
-        public CompletionItem createKeywordItem(String kwd, String postfix, int substitutionOffset, boolean smartType) {
-            CompletionItem item = new CompletionItem(kwd);
-            item.setKind(CompletionItemKind.Keyword);
-            item.setSortText(String.format("%4d%s", smartType ? 670 : 1670, kwd)); //NOI18N
-            return item;
-        }
-
-        @Override
-        public CompletionItem createPackageItem(String pkgFQN, int substitutionOffset, boolean inPackageStatement) {
-            final String simpleName = pkgFQN.substring(pkgFQN.lastIndexOf('.') + 1);
-            CompletionItem item = new CompletionItem(simpleName);
-            item.setKind(CompletionItemKind.Folder);
-            item.setSortText(String.format("%4d%s#%s", 1900, simpleName, pkgFQN)); //NOI18N
-            return item;
-        }
-
-        @Override
-        public CompletionItem createTypeItem(CompilationInfo info, TypeElement elem, DeclaredType type, int substitutionOffset, ReferencesCount referencesCount, boolean isDeprecated, boolean insideNew, boolean addTypeVars, boolean addSimpleName, boolean smartType, boolean autoImportEnclosingType) {
-            CompletionItem item = new CompletionItem(elem.getSimpleName().toString());
-            item.setKind(elementKind2CompletionItemKind(elem.getKind()));
-            String name = elem.getQualifiedName().toString();
-            int idx = name.lastIndexOf('.');
-            String pkgName = idx < 0 ? "" : name.substring(0, idx);
-            if (!pkgName.isEmpty()) {
-                item.setDetail(name.substring(0, idx));
-            }
-            item.setSortText(String.format("%4d%s#%2d#%s", smartType ? 800 : 1800, elem.getSimpleName().toString(), Utilities.getImportanceLevel(name), pkgName)); //NOI18N
-            setCompletionData(item, elem);
-            return item;
-        }
-
-        @Override
-        public CompletionItem createTypeItem(ElementHandle<TypeElement> handle, EnumSet<ElementKind> kinds, int substitutionOffset, ReferencesCount referencesCount, Source source, boolean insideNew, boolean addTypeVars, boolean afterExtends) {
-            TypeElement te = handle.resolve(info);
-            if (te != null && info.getTrees().isAccessible(scope, te)) {
-                CompletionItem item = new CompletionItem(te.getSimpleName().toString());
-                String name = handle.getQualifiedName();
-                int idx = name.lastIndexOf('.');
-                String pkgName = idx < 0 ? "" : name.substring(0, idx);
-                if (!pkgName.isEmpty()) {
-                    item.setDetail(pkgName);
-                }
-                item.setKind(elementKind2CompletionItemKind(handle.getKind()));
-                item.setSortText(String.format("%4d%s#%2d#%s", 1800, te.getSimpleName().toString(), Utilities.getImportanceLevel(name), pkgName)); //NOI18N
-                setCompletionData(item, handle);
-                return item;
-            }
-            return null;
-        }
-
-        @Override
-        public CompletionItem createArrayItem(CompilationInfo info, ArrayType type, int substitutionOffset, ReferencesCount referencesCount, Elements elements) {
-            return null; //TODO: fill
-        }
-
-        @Override
-        public CompletionItem createTypeParameterItem(TypeParameterElement elem, int substitutionOffset) {
-            CompletionItem item = new CompletionItem(elem.getSimpleName().toString());
-            item.setKind(elementKind2CompletionItemKind(elem.getKind()));
-            item.setSortText(String.format("%4d%s", 1700, elem.getSimpleName().toString())); //NOI18N
-            return item;
-        }
-
-        @Override
-        public CompletionItem createVariableItem(CompilationInfo info, VariableElement elem, TypeMirror type, int substitutionOffset, ReferencesCount referencesCount, boolean isInherited, boolean isDeprecated, boolean smartType, int assignToVarOffset) {
-            CompletionItem item = new CompletionItem(elem.getSimpleName().toString());
-            item.setKind(elementKind2CompletionItemKind(elem.getKind()));
-            int priority = elem.getKind() == ElementKind.ENUM_CONSTANT || elem.getKind() == ElementKind.FIELD ? smartType ? 300 : 1300 : smartType ? 200 : 1200;
-            item.setSortText(String.format("%4d%s", priority, elem.getSimpleName().toString())); //NOI18N
-            setCompletionData(item, elem);
-            return item;
-        }
-
-        @Override
-        public CompletionItem createVariableItem(CompilationInfo info, String varName, int substitutionOffset, boolean newVarName, boolean smartType) {
-            CompletionItem item = new CompletionItem(varName);
-            item.setKind(CompletionItemKind.Variable);
-            item.setSortText(String.format("%4d%s", smartType ? 200 : 1200, varName)); //NOI18N
-            return item;
-        }
-
-        @Override
-        public CompletionItem createExecutableItem(CompilationInfo info, ExecutableElement elem, ExecutableType type, int substitutionOffset, ReferencesCount referencesCount, boolean isInherited, boolean isDeprecated, boolean inImport, boolean addSemicolon, boolean smartType, int assignToVarOffset, boolean memberRef) {
-            Iterator<? extends VariableElement> it = elem.getParameters().iterator();
-            Iterator<? extends TypeMirror> tIt = type.getParameterTypes().iterator();
-            StringBuilder label = new StringBuilder();
-            String sep = "";
-            label.append(elem.getSimpleName().toString());
-            label.append("(");
-            StringBuilder sortParams = new StringBuilder();
-            sortParams.append('(');
-            int cnt = 0;
-            while(it.hasNext() && tIt.hasNext()) {
-                TypeMirror tm = tIt.next();
-                if (tm == null) {
-                    break;
-                }
-                label.append(sep);
-                String paramTypeName = Utilities.getTypeName(info, tm, false, elem.isVarArgs() && !tIt.hasNext()).toString();
-                label.append(paramTypeName);
-                label.append(' ');
-                label.append(it.next().getSimpleName().toString());
-                sep = ", ";
-                sortParams.append(paramTypeName);
-                if (tIt.hasNext()) {
-                    sortParams.append(',');
-                }
-                cnt++;
-            }
-            label.append(") : ");
-            sortParams.append(')');
-            TypeMirror retType = type.getReturnType();
-            label.append(Utilities.getTypeName(info, retType, false).toString());
-            CompletionItem item = new CompletionItem(label.toString());
-            item.setKind(elementKind2CompletionItemKind(elem.getKind()));
-            StringBuilder insertText = new StringBuilder();
-            insertText.append(elem.getSimpleName());
-            insertText.append("(");
-            if (elem.getParameters().isEmpty()) {
-                insertText.append(")");
-            }
-            item.setInsertText(insertText.toString());
-            item.setInsertTextFormat(InsertTextFormat.PlainText);
-            int priority = elem.getKind() == ElementKind.METHOD ? smartType ? 500 : 1500 : smartType ? 650 : 1650;
-            item.setSortText(String.format("%4d%s#%2d%s", priority, elem.getSimpleName().toString(), cnt, sortParams)); //NOI18N
-            setCompletionData(item, elem);
-            return item;
-        }
-
-        @Override
-        public CompletionItem createThisOrSuperConstructorItem(CompilationInfo info, ExecutableElement elem, ExecutableType type, int substitutionOffset, boolean isDeprecated, String name) {
-            CompletionItem item = createExecutableItem(info, elem, type, substitutionOffset, null, false, isDeprecated, false, false, false, -1, false);
-            item.setLabel(name != null ? name : elem.getEnclosingElement().getSimpleName().toString());
-            StringBuilder insertText = new StringBuilder();
-            insertText.append(item.getLabel());
-            insertText.append("(");
-            if (elem.getParameters().isEmpty()) {
-                insertText.append(")");
-            }
-            item.setInsertText(insertText.toString());
-            item.setKind(CompletionItemKind.Constructor);
-            item.setSortText(String.format("%4d%s", name != null ? 1550 : 1650, item.getSortText().substring(4))); //NOI18N
-            setCompletionData(item, elem);
-            return item;
-        }
-
-        @Override
-        public CompletionItem createOverrideMethodItem(CompilationInfo info, ExecutableElement elem, ExecutableType type, int substitutionOffset, boolean implement) {
-            CompletionItem item = createExecutableItem(info, elem, type, substitutionOffset, null, false, false, false, false, false, -1, false);
-            item.setLabel(String.format("%s - %s", item.getLabel(), implement ? "implement" : "override"));
-            item.setInsertText(null);
-            item.setKind(elementKind2CompletionItemKind(elem.getKind()));
-            try {
-                List<TextEdit> textEdits = modify2TextEdits(JavaSource.forFileObject(info.getFileObject()), wc -> {
-                    wc.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED);
-                    TreePath tp = wc.getTreeUtilities().pathFor(offset);
-                    if (implement) {
-                        GeneratorUtils.generateAbstractMethodImplementation(wc, tp, elem, offset);
-                    } else {
-                        GeneratorUtils.generateMethodOverride(wc, tp, elem, offset);
-                    }
-                });
-                if (!textEdits.isEmpty()) {
-                    item.setTextEdit(textEdits.get(0));
-                }
-            } catch (IOException ex) {
-                //TODO: include stack trace:
-                client.logMessage(new MessageParams(MessageType.Error, ex.getMessage()));
-            }
-            setCompletionData(item, elem);
-            return item;
-        }
-
-        @Override
-        public CompletionItem createGetterSetterMethodItem(CompilationInfo info, VariableElement elem, TypeMirror type, int substitutionOffset, String name, boolean setter) {
-            return null; //TODO: fill
-        }
-
-        @Override
-        public CompletionItem createDefaultConstructorItem(TypeElement elem, int substitutionOffset, boolean smartType) {
-            return null; //TODO: fill
-        }
-
-        @Override
-        public CompletionItem createParametersItem(CompilationInfo info, ExecutableElement elem, ExecutableType type, int substitutionOffset, boolean isDeprecated, int activeParamIndex, String name) {
-            return null; //TODO: fill
-        }
-
-        @Override
-        public CompletionItem createAnnotationItem(CompilationInfo info, TypeElement elem, DeclaredType type, int substitutionOffset, ReferencesCount referencesCount, boolean isDeprecated) {
-            return null; //TODO: fill
-        }
-
-        @Override
-        public CompletionItem createAttributeItem(CompilationInfo info, ExecutableElement elem, ExecutableType type, int substitutionOffset, boolean isDeprecated) {
-            CompletionItem item = new CompletionItem(elem.getSimpleName().toString());
-            item.setKind(CompletionItemKind.Property);
-            StringBuilder insertText = new StringBuilder();
-            insertText.append(elem.getSimpleName());
-            insertText.append("=");
-            item.setInsertText(insertText.toString());
-            item.setInsertTextFormat(InsertTextFormat.PlainText);
-            int priority = isDeprecated ? 100 + DEPRECATED : 100;
-            item.setSortText(String.format("%4d%s", priority, elem.getSimpleName().toString()));
-            setCompletionData(item, elem);
-            return item;
-        }
-
-        @Override
-        public CompletionItem createAttributeValueItem(CompilationInfo info, String value, String documentation, TypeElement element, int substitutionOffset, ReferencesCount referencesCount) {
-            CompletionItem item = new CompletionItem(value);
-            item.setKind(CompletionItemKind.Text);
-            item.setSortText(value);
-            item.setDocumentation(documentation);
-            return item;
-        }
-
-        private static final Object KEY_IMPORT_TEXT_EDITS = new Object();
-
-        @Override
-        public CompletionItem createStaticMemberItem(CompilationInfo info, DeclaredType type, Element memberElem, TypeMirror memberType, boolean multipleVersions, int substitutionOffset, boolean isDeprecated, boolean addSemicolon) {
-            //TODO: prefer static imports (but would be much slower?)
-            //TODO: should be resolveImport instead of addImports:
-            Map<Element, List<TextEdit>> imports = (Map<Element, List<TextEdit>>) info.getCachedValue(KEY_IMPORT_TEXT_EDITS);
-            if (imports == null) {
-                info.putCachedValue(KEY_IMPORT_TEXT_EDITS, imports = new HashMap<>(), CacheClearPolicy.ON_TASK_END);
-            }
-            List<TextEdit> currentClassImport = imports.computeIfAbsent(type.asElement(), toImport -> {
-                try {
-                    return modify2TextEdits(JavaSource.forFileObject(info.getFileObject()), wc -> {
-                        wc.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED);
-                        wc.rewrite(info.getCompilationUnit(), GeneratorUtilities.get(wc).addImports(wc.getCompilationUnit(), new HashSet<>(Arrays.asList(toImport))));
-                    });
-                } catch (IOException ex) {
-                    //TODO: include stack trace:
-                    client.logMessage(new MessageParams(MessageType.Error, ex.getMessage()));
-                    return Collections.emptyList();
-                }
-            });
-            String label = type.asElement().getSimpleName() + "." + memberElem.getSimpleName();
-            CompletionItem item = new CompletionItem(label);
-            item.setKind(elementKind2CompletionItemKind(memberElem.getKind()));
-            item.setInsertText(label);
-            item.setInsertTextFormat(InsertTextFormat.PlainText);
-            item.setAdditionalTextEdits(currentClassImport);
-            String sortText = memberElem.getSimpleName().toString();
-            if (memberElem.getKind().isField()) {
-                sortText += String.format("#%s", Utilities.getTypeName(info, type, false)); //NOI18N
-            } else {
-                StringBuilder sortParams = new StringBuilder();
-                sortParams.append('(');
-                int cnt = 0;
-                Iterator<? extends TypeMirror> tIt = ((ExecutableType)memberType).getParameterTypes().iterator();
-                while(tIt.hasNext()) {
-                    TypeMirror tm = tIt.next();
-                    if (tm == null) {
-                        break;
-                    }
-                    sortParams.append(Utilities.getTypeName(info, tm, false, ((ExecutableElement)memberElem).isVarArgs() && !tIt.hasNext()).toString());
-                    if (tIt.hasNext()) {
-                        sortParams.append(',');
-                    }
-                    cnt++;
-                }
-                sortParams.append(')');
-                sortText += String.format("#%2d#%s#s", cnt, sortParams.toString(), Utilities.getTypeName(info, type, false)); //NOI18N
-            }
-            item.setSortText(String.format("%4d%s", memberElem.getKind().isField() ? 720 : 750, sortText)); //NOI18N
-            setCompletionData(item, memberElem);
-            return item;
-        }
-
-        @Override
-        public CompletionItem createStaticMemberItem(ElementHandle<TypeElement> handle, String name, int substitutionOffset, boolean addSemicolon, ReferencesCount referencesCount, Source source) {
-            return null; //TODO: fill
-        }
-
-        @Override
-        public CompletionItem createChainedMembersItem(CompilationInfo info, List<? extends Element> chainedElems, List<? extends TypeMirror> chainedTypes, int substitutionOffset, boolean isDeprecated, boolean addSemicolon) {
-            return null; //TODO: fill
-        }
-
-        @Override
-        public CompletionItem createInitializeAllConstructorItem(CompilationInfo info, boolean isDefault, Iterable<? extends VariableElement> fields, ExecutableElement superConstructor, TypeElement parent, int substitutionOffset) {
-            return null; //TODO: fill
-        }
-
-        private static CompletionItemKind elementKind2CompletionItemKind(ElementKind kind) {
-            switch (kind) {
-                case PACKAGE:
-                    return CompletionItemKind.Folder;
-                case ENUM:
-                    return CompletionItemKind.Enum;
-                case CLASS:
-                    return CompletionItemKind.Class;
-                case ANNOTATION_TYPE:
-                    return CompletionItemKind.Interface;
-                case INTERFACE:
-                    return CompletionItemKind.Interface;
-                case ENUM_CONSTANT:
-                    return CompletionItemKind.EnumMember;
-                case FIELD:
-                    return CompletionItemKind.Field;
-                case PARAMETER:
-                    return CompletionItemKind.Variable;
-                case LOCAL_VARIABLE:
-                    return CompletionItemKind.Variable;
-                case EXCEPTION_PARAMETER:
-                    return CompletionItemKind.Variable;
-                case METHOD:
-                    return CompletionItemKind.Method;
-                case CONSTRUCTOR:
-                    return CompletionItemKind.Constructor;
-                case TYPE_PARAMETER:
-                    return CompletionItemKind.TypeParameter;
-                case RESOURCE_VARIABLE:
-                    return CompletionItemKind.Variable;
-                case MODULE:
-                    return CompletionItemKind.Module;
-                case STATIC_INIT:
-                case INSTANCE_INIT:
-                case OTHER:
-                default:
-                    return CompletionItemKind.Text;
-            }
-        }
-    }
-
     private static final RequestProcessor JAVADOC_WORKER = new RequestProcessor(TextDocumentServiceImpl.class.getName() + ".javadoc", 1);
 
     @Override
     public CompletableFuture<CompletionItem> resolveCompletionItem(CompletionItem ci) {
         JsonObject rawData = (JsonObject) ci.getData();
-        if (rawData == null) {
-            return CompletableFuture.completedFuture(ci);
-        }
-        CompletionData data = new Gson().fromJson(rawData, CompletionData.class);
-        try {
-            FileObject file = fromURI(data.uri);
-            if (file == null) {
-                return CompletableFuture.completedFuture(ci);
-            }
-            EditorCookie ec = file.getLookup().lookup(EditorCookie.class);
-            Document doc = ec.openDocument();
-            final ElementHandle<Element> handle = ElementHandleAccessor.getInstance().create(ElementKind.valueOf(data.kind), data.elementHandle);
-            final JavaDocumentationTask<Future<String>> task = JavaDocumentationTask.create(-1, handle, new JavaDocumentationTask.DocumentationFactory<Future<String>>() {
-                @Override
-                public Future<String> create(CompilationInfo compilationInfo, Element element, Callable<Boolean> cancel) {
-                    return ElementJavadoc.create(compilationInfo, element, cancel).getTextAsync();
+        if (rawData != null) {
+            CompletionData data = new Gson().fromJson(rawData, CompletionData.class);
+            Completion completion = lastCompletions.get(data.index);
+            if (completion != null) {
+                FileObject file = fromURI(data.uri);
+                if (file == null) {
+                    return CompletableFuture.completedFuture(ci);
                 }
-            }, () -> false);
-            LineMap[] lm = new LineMap[1];
-            ModificationResult mr = ModificationResult.runModificationTask(Collections.singletonList(Source.create(doc)), new UserTask() {
-                @Override
-                public void run(ResultIterator resultIterator) throws Exception {
-                    task.run(resultIterator);
-                    if (ci.getDetail() != null) {
-                        final WorkingCopy copy = WorkingCopy.get(resultIterator.getParserResult(data.offset));
-                        copy.toPhase(JavaSource.Phase.RESOLVED);
-                        Element e = handle.resolve(copy);
-                        if (e != null) {
-                            copy.rewrite(copy.getCompilationUnit(), GeneratorUtilities.get(copy).addImports(copy.getCompilationUnit(), Collections.singleton(e)));
+                if (completion.getDetail() != null) {
+                    try {
+                        String detail = completion.getDetail().get();
+                        if (detail != null) {
+                            ci.setDetail(detail);
                         }
-                        lm[0] = copy.getCompilationUnit().getLineMap();
+                    } catch (Exception ex) {
                     }
                 }
-            });
-            List<? extends ModificationResult.Difference> diffs = mr.getDifferences(file);
-            if (diffs != null && !diffs.isEmpty()) {
-                List<TextEdit> edits = new ArrayList<>();
-                for (ModificationResult.Difference diff : diffs) {
-                    edits.add(new TextEdit(new Range(Utils.createPosition(lm[0], diff.getStartPosition().getOffset()),
-                            Utils.createPosition(lm[0], diff.getEndPosition().getOffset())), diff.getNewText()));
+                if (completion.getDocumentation() != null) {
+                    try {
+                        String documentation = completion.getDocumentation().get();
+                        if (documentation != null) {
+                            MarkupContent markup = new MarkupContent();
+                            markup.setKind("markdown");
+                            markup.setValue(html2MD(documentation));
+                            ci.setDocumentation(markup);
+                        }
+                    } catch (Exception ex) {
+                    }
                 }
-                ci.setAdditionalTextEdits(edits);
-            }
-            Future<String> futureJavadoc = task.getDocumentation();
-            CompletableFuture<CompletionItem> result = new CompletableFuture<CompletionItem>() {
-                @Override
-                public boolean cancel(boolean mayInterruptIfRunning) {
-                    return futureJavadoc.cancel(mayInterruptIfRunning) && super.cancel(mayInterruptIfRunning);
+                if (completion.getAdditionalTextEdits() != null) {
+                    try {
+                        List<org.netbeans.api.lsp.TextEdit> additionalTextEdits = completion.getAdditionalTextEdits().get();
+                        if (additionalTextEdits != null) {
+                            ci.setAdditionalTextEdits(additionalTextEdits.stream().map(ed -> {
+                                return new TextEdit(new Range(Utils.createPosition(file, ed.getStartOffset()), Utils.createPosition(file, ed.getEndOffset())), ed.getNewText());
+                            }).collect(Collectors.toList()));
+                        }
+                    } catch (Exception ex) {
+                    }
                 }
-            };
 
-            JAVADOC_WORKER.post(() -> {
-                try {
-                    String javadoc = futureJavadoc.get();
-                    MarkupContent markup = new MarkupContent();
-                    markup.setKind("markdown");
-                    markup.setValue(html2MD(javadoc));
-                    ci.setDocumentation(markup);
-                    result.complete(ci);
-                } catch (ExecutionException | InterruptedException ex) {
-                    result.completeExceptionally(ex);
-                }
-            });
-            return result;
-        } catch (IOException | ParseException ex) {
-            CompletableFuture<CompletionItem> result = new CompletableFuture<CompletionItem>();
-            result.completeExceptionally(ex);
-            return result;
+            }
         }
+        return CompletableFuture.completedFuture(ci);
     }
 
     public static String html2MD(String html) {
@@ -864,30 +497,25 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli
 
     @Override
     public CompletableFuture<Either<List<? extends Location>, List<? extends LocationLink>>> definition(DefinitionParams params) {
-        String uri = params.getTextDocument().getUri();
-        JavaSource js = getJavaSource(uri);
-        if (js == null) {
-            return CompletableFuture.completedFuture(Either.forLeft(new ArrayList<>()));
-        }
-        GoToTarget[] target = new GoToTarget[1];
-        LineMap[] thisFileLineMap = new LineMap[1];
         try {
-            js.runUserActionTask(cc -> {
-                cc.toPhase(JavaSource.Phase.RESOLVED);
-                Document doc = cc.getSnapshot().getSource().getDocument(true);
-                int offset = Utils.getOffset(doc, params.getPosition());
-                Context context = GoToSupport.resolveContext(cc, doc, offset, false, false);
-                if (context == null) {
-                    return ;
+            String uri = params.getTextDocument().getUri();
+            Document doc = openedDocuments.get(uri);
+            if (doc != null) {
+                FileObject file = Utils.fromUri(uri);
+                if (file != null) {
+                    int offset = Utils.getOffset(doc, params.getPosition());
+                    return HyperlinkLocation.resolve(doc, offset).thenApply(locs -> {
+                        return Either.forLeft(locs.stream().map(location -> {
+                            FileObject fo = location.getFileObject();
+                            return new Location(Utils.toUri(fo), new Range(Utils.createPosition(fo, location.getStartOffset()), Utils.createPosition(fo, location.getEndOffset())));
+                        }).collect(Collectors.toList()));
+                    });
                 }
-                target[0] = GoToSupport.computeGoToTarget(cc, context, offset);
-                thisFileLineMap[0] = cc.getCompilationUnit().getLineMap();
-            }, true);
-        } catch (IOException ex) {
-            //TODO: include stack trace:
+            }
+        } catch (MalformedURLException ex) {
             client.logMessage(new MessageParams(MessageType.Error, ex.getMessage()));
         }
-        return gotoTarget2Location(uri, target[0], thisFileLineMap[0]).thenApply(location -> Either.forLeft(location != null ? Collections.singletonList(location) : Collections.emptyList()));
+        return CompletableFuture.completedFuture(Either.forLeft(Collections.emptyList()));
     }
 
     @Override
@@ -976,8 +604,9 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli
 
     @Override
     public CompletableFuture<List<? extends Location>> references(ReferenceParams params) {
+        final Project[] projects = server.openedProjects().getNow(null);
         // shortcut: if the projects are not yet initialized, return empty:
-        if (server.openedProjects().getNow(null) == null) {
+        if (projects == null) {
             return CompletableFuture.completedFuture(Collections.emptyList());
         }
         AtomicBoolean cancel = new AtomicBoolean();
@@ -1040,6 +669,16 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli
                     query[0] = new WhereUsedQuery(Lookups.singleton(TreePathHandle.create(path, cc)));
                 }, true);
                 if (cancel.get()) return ;
+                List<FileObject> sourceRoots = new ArrayList<>();
+                for (Project project : projects) {
+                    Sources sources = ProjectUtils.getSources(project);
+                    for (SourceGroup sourceGroup : sources.getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA)) {
+                        sourceRoots.add(sourceGroup.getRootFolder());
+                    }
+                }
+                if (!sourceRoots.isEmpty()) {
+                    query[0].getContext().add(org.netbeans.modules.refactoring.api.Scope.create(sourceRoots, null, null));
+                }
                 cancelCallback[0] = () -> query[0].cancelRequest();
                 RefactoringSession refactoring = RefactoringSession.create("FindUsages");
                 Problem p;
@@ -1209,7 +848,7 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli
             return CompletableFuture.completedFuture(Collections.emptyList());
         }
         JavaSource js = JavaSource.forDocument(doc);
-        if (doc == null || js == null) {
+        if (js == null) {
             return CompletableFuture.completedFuture(Collections.emptyList());
         }
         Map<String, ErrorDescription> id2Errors = (Map<String, ErrorDescription>) doc.getProperty("lsp-errors");
@@ -1844,42 +1483,44 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli
         GoToTarget[] target = new GoToTarget[1];
         LineMap[] thisFileLineMap = new LineMap[1];
         try {
-            js.runUserActionTask(cc -> {
-                cc.toPhase(JavaSource.Phase.RESOLVED);
-                Document doc = cc.getSnapshot().getSource().getDocument(true);
-                int offset = Utils.getOffset(doc, position);
-                TreeUtilities treeUtilities = cc.getTreeUtilities();
-                TreePath path = treeUtilities.getPathElementOfKind(Kind.METHOD, treeUtilities.pathFor(offset));
-                if (path != null) {
-                    Trees trees = cc.getTrees();
-                    Element resolved = trees.getElement(path);
-                    if (resolved != null && resolved.getKind() == ElementKind.METHOD) {
-                        Map<ElementHandle<? extends Element>, List<ElementDescription>> overriding = new ComputeOverriding(new AtomicBoolean()).process(cc);
-                        List<ElementDescription> eds = overriding.get(ElementHandle.create(resolved));
-                        if (eds != null) {
-                            Iterator<ElementDescription> it = eds.iterator();
-                            if (it.hasNext()) {
-                                ElementDescription ed = it.next();
-                                Element el = ed.getHandle().resolve(cc);
-                                TreePath tp = trees.getPath(el);
-                                long startPos = tp != null && cc.getCompilationUnit() == tp.getCompilationUnit() ? trees.getSourcePositions().getStartPosition(cc.getCompilationUnit(), tp.getLeaf()) : -1;
-                                if (startPos >= 0) {
-                                    long endPos = trees.getSourcePositions().getEndPosition(cc.getCompilationUnit(), tp.getLeaf());
-                                    target[0] = new GoToTarget(cc.getSnapshot().getOriginalOffset((int) startPos),
-                                            cc.getSnapshot().getOriginalOffset((int) endPos), GoToSupport.getNameSpan(tp.getLeaf(), treeUtilities),
-                                            null, null, null, ed.getDisplayName(), true);
-                                } else {
-                                    TypeElement te = el != null ? cc.getElementUtilities().outermostTypeElement(el) : null;
-                                    target[0] = new GoToTarget(-1, -1, null, cc.getClasspathInfo(),ed.getHandle(),
-                                            te != null ? te.getQualifiedName().toString().replace('.', '/') + ".class" : null,
-                                            ed.getDisplayName(), true);
+            if (js != null) {
+                js.runUserActionTask(cc -> {
+                    cc.toPhase(JavaSource.Phase.RESOLVED);
+                    Document doc = cc.getSnapshot().getSource().getDocument(true);
+                    int offset = Utils.getOffset(doc, position);
+                    TreeUtilities treeUtilities = cc.getTreeUtilities();
+                    TreePath path = treeUtilities.getPathElementOfKind(Kind.METHOD, treeUtilities.pathFor(offset));
+                    if (path != null) {
+                        Trees trees = cc.getTrees();
+                        Element resolved = trees.getElement(path);
+                        if (resolved != null && resolved.getKind() == ElementKind.METHOD) {
+                            Map<ElementHandle<? extends Element>, List<ElementDescription>> overriding = new ComputeOverriding(new AtomicBoolean()).process(cc);
+                            List<ElementDescription> eds = overriding.get(ElementHandle.create(resolved));
+                            if (eds != null) {
+                                Iterator<ElementDescription> it = eds.iterator();
+                                if (it.hasNext()) {
+                                    ElementDescription ed = it.next();
+                                    Element el = ed.getHandle().resolve(cc);
+                                    TreePath tp = trees.getPath(el);
+                                    long startPos = tp != null && cc.getCompilationUnit() == tp.getCompilationUnit() ? trees.getSourcePositions().getStartPosition(cc.getCompilationUnit(), tp.getLeaf()) : -1;
+                                    if (startPos >= 0) {
+                                        long endPos = trees.getSourcePositions().getEndPosition(cc.getCompilationUnit(), tp.getLeaf());
+                                        target[0] = new GoToTarget(cc.getSnapshot().getOriginalOffset((int) startPos),
+                                                cc.getSnapshot().getOriginalOffset((int) endPos), GoToSupport.getNameSpan(tp.getLeaf(), treeUtilities),
+                                                null, null, null, ed.getDisplayName(), true);
+                                    } else {
+                                        TypeElement te = el != null ? cc.getElementUtilities().outermostTypeElement(el) : null;
+                                        target[0] = new GoToTarget(-1, -1, null, cc.getClasspathInfo(),ed.getHandle(),
+                                                te != null ? te.getQualifiedName().toString().replace('.', '/') + ".class" : null,
+                                                ed.getDisplayName(), true);
+                                    }
                                 }
                             }
+                            thisFileLineMap[0] = cc.getCompilationUnit().getLineMap();
                         }
-                        thisFileLineMap[0] = cc.getCompilationUnit().getLineMap();
                     }
-                }
-            }, true);
+                }, true);
+            }
         } catch (IOException ex) {
             client.logMessage(new MessageParams(MessageType.Error, ex.getMessage()));
         }
@@ -1890,66 +1531,14 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli
         Location location = null;
         if (target != null && target.success) {
             if (target.offsetToOpen < 0) {
-                Object[] openInfo = ElementOpenAccessor.getInstance().getOpenInfo(target.cpInfo, target.elementToOpen, new AtomicBoolean());
-                if (openInfo == null && target.resourceName != null) {
-                    // try to attach sources
-                    final ClassPath cp = ClassPathSupport.createProxyClassPath(
-                            target.cpInfo.getClassPath(ClasspathInfo.PathKind.BOOT),
-                            target.cpInfo.getClassPath(ClasspathInfo.PathKind.COMPILE),
-                            target.cpInfo.getClassPath(ClasspathInfo.PathKind.SOURCE));
-                    final FileObject resource = cp.findResource(target.resourceName);
-                    if (resource != null) {
-                        final FileObject root = cp.findOwnerRoot(resource);
-                        if (root != null) {
-                            final CompletableFuture<Location> future = new CompletableFuture<>();
-                            SourceJavadocAttacher.attachSources(root.toURL(), new SourceJavadocAttacher.AttachmentListener() {
-                                @Override
-                                public void attachmentSucceeded() {
-                                    Object[] openInfo = ElementOpenAccessor.getInstance().getOpenInfo(target.cpInfo, target.elementToOpen, new AtomicBoolean());
-                                    if (openInfo != null && (int) openInfo[1] != (-1) && (int) openInfo[2] != (-1) && openInfo[3] != null) {
-                                        future.complete(openInfo2Location(openInfo));
-                                    } else {
-                                        attachmentFailed();
-                                    }
-                                }
-
-                                @Override
-                                public void attachmentFailed() {
-                                    try {
-                                        FileObject generated = org.netbeans.modules.java.classfile.CodeGenerator.generateCode(target.cpInfo, target.elementToOpen);
-                                        if (generated != null) {
-                                            final int[] pos = new int[] {-1};
-                                            try {
-                                                JavaSource.create(target.cpInfo, generated).runUserActionTask(new Task<CompilationController>() {
-                                                    @Override public void run(CompilationController parameter) throws Exception {
-                                                        parameter.toPhase(JavaSource.Phase.RESOLVED);
-                                                        Element el = target.elementToOpen.resolve(parameter);
-                                                        if (el != null) {
-                                                            TreePath p = parameter.getTrees().getPath(el);
-                                                            if (p != null) {
-                                                                pos[0] = (int) parameter.getTrees().getSourcePositions().getStartPosition(p.getCompilationUnit(), p.getLeaf());
-                                                            }
-                                                        }
-                                                    }
-                                                }, true);
-                                            } catch (IOException ex) {
-                                            }
-                                            int offset = pos[0] != -1 ? pos[0] : 0;
-                                            future.complete(new Location(Utils.toUri(generated), new Range(Utils.createPosition(generated, offset), Utils.createPosition(generated, offset))));
-                                            return;
-                                        }
-                                    } catch (Exception e) {
-                                    }
-                                    future.complete(null);
-                                }
-                            });
-                            return future;
-                        }
+                final CompletableFuture<HyperlinkLocation> future = ElementOpen.getLocation(target.cpInfo, target.elementToOpen, target.resourceName);
+                return future.thenApply(loc -> {
+                    if (loc != null) {
+                        FileObject fo = loc.getFileObject();
+                        return new Location(Utils.toUri(fo), new Range(Utils.createPosition(fo, loc.getStartOffset()), Utils.createPosition(fo, loc.getEndOffset())));
                     }
-                }
-                if (openInfo != null && (int) openInfo[1] != (-1) && (int) openInfo[2] != (-1) && openInfo[3] != null) {
-                    location = openInfo2Location(openInfo);
-                }
+                    return null;
+                });
             } else {
                 int start = target.nameSpan != null ? target.nameSpan[0] : target.offsetToOpen;
                 int end = target.nameSpan != null ? target.nameSpan[1] : target.endPos;
@@ -1959,20 +1548,6 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli
         return CompletableFuture.completedFuture(location);
     }
 
-    private Location openInfo2Location(Object[] openInfo) {
-        FileObject file = (FileObject) openInfo[0];
-        int start = (int) openInfo[3];
-        if (start < 0) {
-            start = (int) openInfo[1];
-        }
-        int end = (int) openInfo[4];
-        if (end < 0) {
-            end = (int) openInfo[2];
-        }
-        LineMap lm = (LineMap) openInfo[5];
-        return new Location(Utils.toUri(file), new Range(Utils.createPosition(lm, start), Utils.createPosition(lm, end)));
-    }
-
     private void runDiagnoticTasks(String uri) {
         if (server.openedProjects().getNow(null) == null) {
             return;
@@ -2015,47 +1590,49 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageCli
                 @Override
                 public void run(ResultIterator it) throws Exception {
                     CompilationController cc = CompilationController.get(it.getParserResult());
-                    cc.toPhase(JavaSource.Phase.RESOLVED);
-                    Map<String, ErrorDescription> id2Errors = new HashMap<>();
-                    List<Diagnostic> diags = new ArrayList<>();
-                    int idx = 0;
-                    List<ErrorDescription> errors = produceErrors.computeErrors(cc, doc);
-                    if (errors == null) {
-                        errors = Collections.emptyList();
-                    }
-                    for (ErrorDescription err : errors) {
-                        Diagnostic diag = new Diagnostic(new Range(Utils.createPosition(cc.getCompilationUnit(), err.getRange().getBegin().getOffset()),
-                                                                   Utils.createPosition(cc.getCompilationUnit(), err.getRange().getEnd().getOffset())),
-                                                         err.getDescription());
-                        switch (err.getSeverity()) {
-                            case ERROR: diag.setSeverity(DiagnosticSeverity.Error); break;
-                            case VERIFIER:
-                            case WARNING: diag.setSeverity(DiagnosticSeverity.Warning); break;
-                            case HINT: diag.setSeverity(DiagnosticSeverity.Hint); break;
-                            default: diag.setSeverity(DiagnosticSeverity.Information); break;
+                    if (cc != null) {
+                        cc.toPhase(JavaSource.Phase.RESOLVED);
+                        Map<String, ErrorDescription> id2Errors = new HashMap<>();
+                        List<Diagnostic> diags = new ArrayList<>();
+                        int idx = 0;
+                        List<ErrorDescription> errors = produceErrors.computeErrors(cc, doc);
+                        if (errors == null) {
+                            errors = Collections.emptyList();
                         }
-                        String id = keyPrefix + ":" + idx++ + "-" + err.getId();
-                        diag.setCode(id);
-                        id2Errors.put(id, err);
-                        diags.add(diag);
-                    }
-                    doc.putProperty("lsp-errors-" + keyPrefix, id2Errors);
-                    doc.putProperty("lsp-errors-diags-" + keyPrefix, diags);
-                    Map<String, ErrorDescription> mergedId2Errors = new HashMap<>();
-                    List<Diagnostic> mergedDiags = new ArrayList<>();
-                    for (String k : ERROR_KEYS) {
-                        Map<String, ErrorDescription> prevErrors = (Map<String, ErrorDescription>) doc.getProperty("lsp-errors-" + k);
-                        if (prevErrors != null) {
-                            mergedId2Errors.putAll(prevErrors);
+                        for (ErrorDescription err : errors) {
+                            Diagnostic diag = new Diagnostic(new Range(Utils.createPosition(cc.getCompilationUnit(), err.getRange().getBegin().getOffset()),
+                                                                       Utils.createPosition(cc.getCompilationUnit(), err.getRange().getEnd().getOffset())),
+                                                             err.getDescription());
+                            switch (err.getSeverity()) {
+                                case ERROR: diag.setSeverity(DiagnosticSeverity.Error); break;
+                                case VERIFIER:
+                                case WARNING: diag.setSeverity(DiagnosticSeverity.Warning); break;
+                                case HINT: diag.setSeverity(DiagnosticSeverity.Hint); break;
+                                default: diag.setSeverity(DiagnosticSeverity.Information); break;
+                            }
+                            String id = keyPrefix + ":" + idx++ + "-" + err.getId();
+                            diag.setCode(id);
+                            id2Errors.put(id, err);
+                            diags.add(diag);
                         }
-                        List<Diagnostic> prevDiags = (List<Diagnostic>) doc.getProperty("lsp-errors-diags-" + k);
-                        if (prevDiags != null) {
-                            mergedDiags.addAll(prevDiags);
+                        doc.putProperty("lsp-errors-" + keyPrefix, id2Errors);
+                        doc.putProperty("lsp-errors-diags-" + keyPrefix, diags);
+                        Map<String, ErrorDescription> mergedId2Errors = new HashMap<>();
+                        List<Diagnostic> mergedDiags = new ArrayList<>();
+                        for (String k : ERROR_KEYS) {
+                            Map<String, ErrorDescription> prevErrors = (Map<String, ErrorDescription>) doc.getProperty("lsp-errors-" + k);
+                            if (prevErrors != null) {
+                                mergedId2Errors.putAll(prevErrors);
+                            }
+                            List<Diagnostic> prevDiags = (List<Diagnostic>) doc.getProperty("lsp-errors-diags-" + k);
+                            if (prevDiags != null) {
+                                mergedDiags.addAll(prevDiags);
+                            }
                         }
+                        doc.putProperty("lsp-errors", mergedId2Errors);
+                        doc.putProperty("lsp-errors-diags", mergedDiags);
+                        publishDiagnostics(uri, mergedDiags);
                     }
-                    doc.putProperty("lsp-errors", mergedId2Errors);
-                    doc.putProperty("lsp-errors-diags", mergedDiags);
-                    publishDiagnostics(uri, mergedDiags);
                 }
             });
         } catch (IOException | ParseException ex) {
diff --git a/java/java.lsp.server/vscode/src/extension.ts b/java/java.lsp.server/vscode/src/extension.ts
index 86e6e25..a506037 100644
--- a/java/java.lsp.server/vscode/src/extension.ts
+++ b/java/java.lsp.server/vscode/src/extension.ts
@@ -465,7 +465,7 @@ function doActivateWithJDK(specifiedJDK: string | null, context: ExtensionContex
         // Options to control the language client
         let clientOptions: LanguageClientOptions = {
             // Register the server for java documents
-            documentSelector: ['java'],
+            documentSelector: [{ language: 'java' }, { language: 'yaml', pattern: '**/application.yml' }],
             synchronize: {
                 configurationSection: 'java',
                 fileEvents: [
diff --git a/java/java.sourceui/apichanges.xml b/java/java.sourceui/apichanges.xml
index 20fd173..16f8927 100644
--- a/java/java.sourceui/apichanges.xml
+++ b/java/java.sourceui/apichanges.xml
@@ -84,6 +84,18 @@ is the proper place.
     <!-- ACTUAL CHANGES BEGIN HERE: -->
 
     <changes>
+        <change id="ElementOpenGetLocation">
+            <api name="general"/>
+            <summary>Adding ElementOpen.getLocation(ClasspathInfo, ElementHandle, String)</summary>
+            <version major="1" minor="45"/>
+            <date day="25" month="3" year="2021"/>
+            <author login="dbalek"/>
+            <compatibility addition="yes">
+            </compatibility>
+            <description>
+                 Adding ElementOpen.getLocation(ClasspathInfo, ElementHandle, String) method.
+            </description>
+        </change>
         <change id="ElementOpenForTreePathHandle">
             <api name="general"/>
             <summary>Adding ElementOpen.open(FileObject toSearch, TreePathHandle toOpen)</summary>
diff --git a/java/java.sourceui/nbproject/project.properties b/java/java.sourceui/nbproject/project.properties
index 01b9ec4..1f40101 100644
--- a/java/java.sourceui/nbproject/project.properties
+++ b/java/java.sourceui/nbproject/project.properties
@@ -18,7 +18,7 @@ javadoc.apichanges=${basedir}/apichanges.xml
 javac.compilerargs=-Xlint -Xlint:-serial
 javac.source=1.8
 javadoc.arch=${basedir}/arch.xml
-spec.version.base=1.57.0
+spec.version.base=1.58.0
 
 test.config.stableBTD.includes=**/*Test.class
 test.config.stableBTD.excludes=\
diff --git a/java/java.sourceui/nbproject/project.xml b/java/java.sourceui/nbproject/project.xml
index 33f9b27..9558ec0 100644
--- a/java/java.sourceui/nbproject/project.xml
+++ b/java/java.sourceui/nbproject/project.xml
@@ -105,6 +105,15 @@
                     </run-dependency>
                 </dependency>
                 <dependency>
+                    <code-name-base>org.netbeans.modules.editor.lib</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>3</release-version>
+                        <specification-version>4.19</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
                     <code-name-base>org.netbeans.modules.editor.lib2</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
diff --git a/java/java.sourceui/src/org/netbeans/api/java/source/ui/ElementOpen.java b/java/java.sourceui/src/org/netbeans/api/java/source/ui/ElementOpen.java
index 61db694..2e03553 100644
--- a/java/java.sourceui/src/org/netbeans/api/java/source/ui/ElementOpen.java
+++ b/java/java.sourceui/src/org/netbeans/api/java/source/ui/ElementOpen.java
@@ -23,6 +23,7 @@ import com.sun.source.util.SourcePositions;
 import com.sun.source.util.TreePath;
 import org.netbeans.api.java.source.support.ErrorAwareTreePathScanner;
 import java.io.IOException;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -38,13 +39,16 @@ import org.netbeans.api.editor.fold.FoldHierarchy;
 import org.netbeans.api.editor.fold.FoldUtilities;
 import org.netbeans.api.java.classpath.ClassPath;
 import org.netbeans.api.java.platform.JavaPlatform;
+import org.netbeans.api.java.queries.SourceJavadocAttacher;
 import org.netbeans.api.java.source.*;
 import org.netbeans.api.progress.ProgressUtils;
 import org.netbeans.modules.java.BinaryElementOpen;
+import org.netbeans.modules.java.classfile.CodeGenerator;
 import org.netbeans.modules.java.source.JavaSourceAccessor;
 import org.netbeans.modules.java.source.parsing.ClassParser;
 import org.netbeans.modules.java.source.parsing.FileObjects;
 import org.netbeans.modules.java.source.ui.ElementOpenAccessor;
+import org.netbeans.spi.java.classpath.support.ClassPathSupport;
 import org.openide.awt.StatusDisplayer;
 import org.openide.cookies.EditorCookie;
 import org.openide.filesystems.FileObject;
@@ -276,12 +280,127 @@ public final class ElementOpen {
         }
     }
 
+    /**
+     * Gets location of the {@link Element} corresponding to the given {@link ElementHandle}.
+     *
+     * @param cpInfo ClasspathInfo which should be used for the search
+     * @param el ElementHandle to search
+     * @param resourceName optional resource name to search
+     * @return location of the given element
+     *
+     * @since 1.58
+     */
+    public static CompletableFuture<Location> getLocation(final ClasspathInfo cpInfo, final ElementHandle<? extends Element> el, String resourceName) {
+        final CompletableFuture<Object[]> future = getFutureOpenInfo(cpInfo, el, resourceName, new AtomicBoolean());
+        return future.thenApply(openInfo -> {
+            if (openInfo[0] != null && (int) openInfo[1] != (-1) && (int) openInfo[2] != (-1)) {
+                FileObject file = (FileObject) openInfo[0];
+                int start = (int) openInfo[3];
+                if (start < 0) {
+                    start = (int) openInfo[1];
+                }
+                int end = (int) openInfo[4];
+                if (end < 0) {
+                    end = (int) openInfo[2];
+                }
+                return new Location(file, start, end);
+            }
+            return null;
+        });
+    }
+
+    /**
+     * Represents the location of an element. It is a range inside of a file object.
+     */
+    public static final class Location {
+
+        private final FileObject fileObject;
+        private final int startOffset;
+        private final int endOffset;
+
+        private Location(FileObject fileObject, int startOffset, int endOffset) {
+            this.fileObject = fileObject;
+            this.startOffset = startOffset;
+            this.endOffset = endOffset;
+        }
+
+        /**
+         * The location's file object.
+         *
+         * @return file object
+         */
+        public FileObject getFileObject() {
+            return fileObject;
+        }
+
+        /**
+         * The location's start offset.
+         *
+         * @return offset
+         */
+        public int getStartOffset() {
+            return startOffset;
+        }
+
+        /**
+         * The location's end offset.
+         *
+         * @return offset
+         */
+        public int getEndOffset() {
+            return endOffset;
+        }
+    }
     // Private methods ---------------------------------------------------------
 
     private static boolean isClassFile(@NonNull final FileObject file) {
         return FileObjects.CLASS.equals(file.getExt()) || ClassParser.MIME_TYPE.equals(file.getMIMEType(ClassParser.MIME_TYPE));
     }
 
+    private static CompletableFuture<Object[]> getFutureOpenInfo(final ClasspathInfo cpInfo, final ElementHandle<? extends Element> el, String resourceName, AtomicBoolean cancel) {
+        Object[] openInfo = getOpenInfo(cpInfo, el, cancel);
+        if (openInfo == null && resourceName != null) {
+            // try to attach sources
+            final ClassPath cp = ClassPathSupport.createProxyClassPath(
+                    cpInfo.getClassPath(ClasspathInfo.PathKind.BOOT),
+                    cpInfo.getClassPath(ClasspathInfo.PathKind.COMPILE),
+                    cpInfo.getClassPath(ClasspathInfo.PathKind.SOURCE));
+            final FileObject resource = cp.findResource(resourceName);
+            if (resource != null) {
+                final FileObject root = cp.findOwnerRoot(resource);
+                if (root != null) {
+                    final CompletableFuture<Object[]> future = new CompletableFuture<>();
+                    SourceJavadocAttacher.attachSources(root.toURL(), new SourceJavadocAttacher.AttachmentListener() {
+                        @Override
+                        public void attachmentSucceeded() {
+                            Object[] openInfo = getOpenInfo(cpInfo, el, cancel);
+                            if (openInfo != null && (int) openInfo[1] != (-1) && (int) openInfo[2] != (-1) && openInfo[5] != null) {
+                                future.complete(openInfo);
+                            } else {
+                                attachmentFailed();
+                            }
+                        }
+
+                        @Override
+                        public void attachmentFailed() {
+                            try {
+                                FileObject generated = CodeGenerator.generateCode(cpInfo, el);
+                                if (generated != null) {
+                                    future.complete(getOpenInfo(generated, el, cancel));
+                                    return;
+                                }
+                            } catch (Exception e) {
+                            }
+                            future.complete(null);
+                        }
+                    });
+                    return future;
+                }
+            }
+        }
+        return CompletableFuture.completedFuture(openInfo);
+    }
+
     private static Object[] getOpenInfo(final ClasspathInfo cpInfo, final ElementHandle<? extends Element> el, AtomicBoolean cancel) {
         FileObject fo = SourceUtils.getFile(el, cpInfo);
         if (fo != null && fo.isFolder()) {
diff --git a/java/refactoring.java/src/org/netbeans/modules/refactoring/java/plugins/JavaWhereUsedQueryPlugin.java b/java/refactoring.java/src/org/netbeans/modules/refactoring/java/plugins/JavaWhereUsedQueryPlugin.java
index e1b7ec1..c617451 100644
--- a/java/refactoring.java/src/org/netbeans/modules/refactoring/java/plugins/JavaWhereUsedQueryPlugin.java
+++ b/java/refactoring.java/src/org/netbeans/modules/refactoring/java/plugins/JavaWhereUsedQueryPlugin.java
@@ -148,7 +148,9 @@ public class JavaWhereUsedQueryPlugin extends JavaRefactoringPlugin implements F
                 final Set<String> packageSet = new HashSet<>(packages.size());
                 for (NonRecursiveFolder nonRecursiveFolder : packages) {
                     String resourceName = cpInfo.getClassPath(ClasspathInfo.PathKind.SOURCE).getResourceName(nonRecursiveFolder.getFolder());
-                    packageSet.add(resourceName.replace('/', '.'));
+                    if (resourceName != null) {
+                        packageSet.add(resourceName.replace('/', '.'));
+                    }
                 }
                 searchScopeType.add(new SearchScopeType() {
                     @Override
diff --git a/nbbuild/antsrc/org/netbeans/nbbuild/extlibs/ignored-overlaps b/nbbuild/antsrc/org/netbeans/nbbuild/extlibs/ignored-overlaps
index b952575..3ba36ae 100644
--- a/nbbuild/antsrc/org/netbeans/nbbuild/extlibs/ignored-overlaps
+++ b/nbbuild/antsrc/org/netbeans/nbbuild/extlibs/ignored-overlaps
@@ -82,9 +82,6 @@ enterprise/javaee7.api/external/javax.annotation-api-1.2.jar enterprise/websvc.r
 enterprise/javaee7.api/external/jaxws-api-2.2.8.jar java/websvc.jaxws21api/external/jaxws-2.2.6-api.zip
 enterprise/javaee7.api/external/jsr181-api-1.0-MR1.jar java/websvc.jaxws21api/external/jaxws-2.2.6-api.zip
 
-# the jcodings is used internally in two unrelated modules:
-ide/libs.bytelist/external/jcodings-1.0.18.jar ide/textmate.lexer/external/jcodings-1.0.18.jar
-
 # ide/lsp.client and java/java.lsp.server both use LSP libraries, but are independent:
 ide/lsp.client/external/org.eclipse.lsp4j-0.9.0.jar java/java.lsp.server/external/org.eclipse.lsp4j-0.9.0.jar
 ide/lsp.client/external/org.eclipse.lsp4j.generator-0.9.0.jar java/java.lsp.server/external/org.eclipse.lsp4j.generator-0.9.0.jar
diff --git a/nbbuild/cluster.properties b/nbbuild/cluster.properties
index b5aee47..4d447b1 100644
--- a/nbbuild/cluster.properties
+++ b/nbbuild/cluster.properties
@@ -311,6 +311,7 @@ nb.cluster.ide.depends=\
 nb.cluster.ide=\
         api.debugger,\
         api.java.classpath,\
+        api.lsp,\
         api.xml,\
         api.xml.ui,\
         bcpg,\
@@ -438,6 +439,7 @@ nb.cluster.ide=\
         libs.graalsdk,\
         libs.ini4j,\
         libs.jaxb,\
+        libs.jcodings,\
         libs.jsch.agentproxy,\
 	libs.json_simple,\
         libs.jvyamlb,\
@@ -821,6 +823,7 @@ nb.cluster.enterprise=\
         libs.jstl,\
         maven.j2ee,\
         maven.jaxws,\
+        micronaut,\
         payara.common,\
         payara.eecommon,\
         payara.jakartaee,\

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists