Skip to content

Commit d21d537

Browse files
committed
Initial spring boot integration
Fixes #50
1 parent aa72674 commit d21d537

11 files changed

+337
-37
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
.cask
2-
tmp/
2+
tmp/
3+
/install/.mvn/wrapper/maven-wrapper.jar

README.md

+89
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,95 @@ some of them are bound to Emacs commands:
116116
#### Classpath browsing
117117
[lsp-java](https://github.com/emacs-lsp/lsp-java) the command `lsp-java-classpath-browse` which allows users to browse the structure of current projects classpath. From that view the users could go to the particular item.
118118
![Classpath](images/classpath.png)
119+
#### STS4 Integration (experimental)
120+
121+
LSP java has integration with [STS4](https://github.com/spring-projects/sts4/) providing the following functionality.
122+
123+
## Spring boot support (Experimental)
124+
125+
In addition to the integration with [Eclipse JDT Language Server](https://projects.eclipse.org/projects/eclipse.jdt.ls) [lsp-java](http://github.com/emacs-lsp/lsp-java) provides integration with [STS4](https://github.com/spring-projects/sts4/) which covers Spring Boot
126+
`application.properties`, `application.yml` and `.java` files.
127+
128+
## Usage:
129+
Make sure that you have configured `JAVA_HOME`. `lsp-java` will automatically download the [STS4](https://github.com/spring-projects/sts4/) when you call `lsp-java-update-server`. In order to enable [STS4](https://github.com/spring-projects/sts4/) integration add the following lines to your config:
130+
``` emacs-lisp
131+
(require 'lsp-java-boot)
132+
133+
;; to enable the lenses
134+
(add-hook 'lsp-mode-hook #'lsp-lens-mode)
135+
(add-hook 'java-mode-hook #'lsp-java-boot-lens-mode)
136+
```
137+
138+
## Functionality for `.java`
139+
140+
### Navigating the source code - Go to symbol in file/workspace
141+
Easy navigation to Spring-specific elements of your source code.
142+
143+
![Go to Symbol in workspace](images/java-navigation.png)
144+
145+
#### Commands
146+
`lsp-workspace-symbol` - (works better usign [helm-lsp](https://github.com/yyoncho/helm-lsp))
147+
148+
#### Examples
149+
* `@/` shows all defined request mappings (mapped path, request method, source location)
150+
* `@+` shows all defined beans (bean name, bean type, source location)
151+
* `@>` shows all functions (prototype implementation)
152+
* `@` shows all Spring annotations in the code
153+
154+
### Quick-access for running apps
155+
Easy navigation to the provided request mappings of running apps.
156+
157+
![accessing running apps quickly](images/running-apps.png)
158+
159+
#### Commands
160+
`lsp-workspace-symbol` - (works better usign [helm-lsp](https://github.com/yyoncho/helm-lsp))
161+
162+
#### Examples
163+
* `//` shows all request mappings of all running Spring Boot apps and opens a browser for the selected endpoint
164+
165+
### Live application information hovers
166+
STS4 automatically detects JVM processes for running boot applications on your local machine.
167+
168+
For some types of information, STS 4 may also show a 'quick summary' as a codelens.
169+
170+
If there are multiple instances of the app running on your machine, the live data from all those instances will show up in the hover information.
171+
172+
``` emacs-lisp
173+
(add-hook 'java-mode-hook #'lsp-java-boot-lens-mode)
174+
```
175+
![live data from running apps as hover on source code](images/live-hovers.png)
176+
177+
#### Examples
178+
* `@Profile`: shows information about the active profiles on the running apps
179+
* `@Component`, `@Bean`, `@Autowired`: shows detailed information about the beans and their wiring from the live app
180+
* `@ContidionalOn...`: shows information about the conditions and their evaluation at runtime
181+
182+
### Code templates
183+
Write Spring code with templates, available via regular code completion.
184+
185+
#### Examples
186+
* `@GetMapping`
187+
* `@PostMapping`
188+
* `@PutMapping`
189+
190+
### Smart code completions
191+
Additional code completions for Spring-specific annotations
192+
193+
![Smart code completion for boot properties](images/validation-completion.png)
194+
195+
## Functionality for `.properties` and `.yml`
196+
197+
This extension analyzes your project's classpath and parses and indexes any [Spring Boot
198+
Properties Metadata](https://docs.spring.io/spring-boot/docs/current/reference/html/configuration-metadata.html) it finds. Both Maven and Gradle projects are supported.
199+
200+
The data in the index is used to provide validation, code completions and information
201+
hovers while editing Spring Boot Properties in either `.properties` or `.yml` format.
202+
203+
### Validation and code completion in properties file
204+
![application-properties-validation](images/validation-completion.png)
205+
206+
### Validation and code completion in yaml file
207+
![application-properties-validation](images/yaml-completion-and-help.png)
119208

120209
#### Spring Initializr
121210
`lsp-java` provides a frontend for [Spring Initializr](https://start.spring.io/) which simplifies the creation of Spring Boot projects directly from Emacs via `lsp-java-spring-initializr`.

images/completion.png

78.9 KB
Loading

images/java-navigation.png

56.9 KB
Loading

images/live-hovers.png

67.5 KB
Loading

images/running-apps.png

45.2 KB
Loading

images/validation-completion.png

76.3 KB
Loading

images/yaml-completion-and-help.png

37 KB
Loading

install/pom.xml

+57
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
<executions>
3232
<execution>
3333
<phase>process-resources</phase>
34+
<id>download-che</id>
3435
<goals>
3536
<goal>wget</goal>
3637
</goals>
@@ -40,6 +41,18 @@
4041
<outputDirectory>${project.build.directory}</outputDirectory>
4142
</configuration>
4243
</execution>
44+
<execution>
45+
<phase>process-resources</phase>
46+
<id>download-vscode</id>
47+
<goals>
48+
<goal>wget</goal>
49+
</goals>
50+
<configuration>
51+
<url>https://marketplace.visualstudio.com/_apis/public/gallery/publishers/Pivotal/vsextensions/vscode-spring-boot/1.3.0/vspackage</url>
52+
<outputFileName>vscode-extension.zip</outputFileName>
53+
<outputDirectory>${project.build.directory}</outputDirectory>
54+
</configuration>
55+
</execution>
4356
</executions>
4457
</plugin>
4558
<plugin>
@@ -53,6 +66,7 @@
5366
<configuration>
5467
<tasks>
5568
<untar src="${project.build.directory}/che-jdt-language-server-latest.tar.gz" compression="gzip" dest="${jdt.js.server.root}"/>
69+
<unzip src="${project.build.directory}/vscode-extension.zip" dest="${project.build.directory}/vscode-extension-extracted"/>
5670
</tasks>
5771
</configuration>
5872
<goals>
@@ -93,6 +107,49 @@
93107
</execution>
94108
</executions>
95109
</plugin>
110+
<plugin>
111+
<artifactId>maven-resources-plugin</artifactId>
112+
<version>3.1.0</version>
113+
<executions>
114+
<execution>
115+
<id>copy-boot-server</id>
116+
<phase>package</phase>
117+
<goals>
118+
<goal>copy-resources</goal>
119+
</goals>
120+
<configuration>
121+
<outputDirectory>${jdt.js.server.root}/boot-server/</outputDirectory>
122+
<resources>
123+
<resource>
124+
<directory>${project.build.directory}/vscode-extension-extracted/extension/jars/</directory>
125+
<includes>
126+
<include>spring-boot-language-server-*.jar</include>
127+
</includes>
128+
</resource>
129+
</resources>
130+
</configuration>
131+
</execution>
132+
<execution>
133+
<id>copy-bundles</id>
134+
<phase>package</phase>
135+
<goals>
136+
<goal>copy-resources</goal>
137+
</goals>
138+
<configuration>
139+
<outputDirectory>${jdt.js.server.root}/bundles/</outputDirectory>
140+
<resources>
141+
<resource>
142+
<directory>${project.build.directory}/vscode-extension-extracted/extension/jars/</directory>
143+
<includes>
144+
<include>jdt-ls-extension.jar</include>
145+
<include>jdt-ls-commons.jar</include>
146+
</includes>
147+
</resource>
148+
</resources>
149+
</configuration>
150+
</execution>
151+
</executions>
152+
</plugin>
96153
</plugins>
97154
</build>
98155
</project>

lsp-java-boot.el

+151
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
;;; lsp-java.el --- Spring boot support for lsp-java
2+
3+
;; Version: 2.0
4+
;; Keywords: java
5+
;; URL: https://github.com/emacs-lsp/lsp-java
6+
7+
;; This program is free software: you can redistribute it and/or modify
8+
;; it under the terms of the GNU General Public License as published by
9+
;; the Free Software Foundation, either version 3 of the License, or
10+
;; (at your option) any later version.
11+
12+
;; This program is distributed in the hope that it will be useful,
13+
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
;; GNU General Public License for more details.
16+
17+
;; You should have received a copy of the GNU General Public License
18+
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
20+
;;; Commentary: LSP Java support for Spring Boot.
21+
22+
;;; Code:
23+
24+
(require 'dash)
25+
(require 'lsp-mode)
26+
(require 'lsp-java)
27+
(require 'cl)
28+
29+
(defcustom lsp-java-boot-enabled t
30+
"If non-nil start the boot server when opening java files."
31+
:group 'lsp-java-boot
32+
:type 'boolean)
33+
34+
(defcustom lsp-java-boot-java-tools-jar nil
35+
"Path to tools jar. If it is not specified it will be calculated using `JAVA_HOME'."
36+
:group 'lsp-java-boot
37+
:type 'file)
38+
39+
(defvar lsp-java-boot--callback nil)
40+
41+
(defun lsp-java-boot--find-tools-jar ()
42+
"Calculate the path to tools.jar."
43+
(let ((tools-jar (or lsp-java-boot-java-tools-jar
44+
(f-join (getenv "JAVA_HOME") "lib/tools.jar"))))
45+
(unless (f-exists? tools-jar)
46+
(error "Please configure either JAVA_HOME or lsp-java-boot-java-tools-jar"))
47+
tools-jar))
48+
49+
(defun lsp-java--sts-javadoc-hover-link (_workspace params)
50+
"Handler for java doc hover."
51+
(with-lsp-workspace (lsp-find-workspace 'jdtls nil)
52+
(lsp-request "workspace/executeCommand"
53+
(list :command "sts.java.addClasspathListener"
54+
:arguments (gethash "callbackCommandId" params))
55+
:no-wait t)))
56+
57+
(defun lsp-java-boot--sts-add-classpath-listener (_workspace params)
58+
(with-lsp-workspace (lsp-find-workspace 'jdtls nil)
59+
(lsp-request "workspace/executeCommand"
60+
(list :command "sts.java.addClasspathListener"
61+
:arguments (gethash "callbackCommandId" params))
62+
:no-wait t)))
63+
64+
(defun lsp-java-boot--workspace-execute-client-command (_jdt-ls-workspace params)
65+
"PARAMS is the classpath info."
66+
(with-lsp-workspace (lsp-find-workspace 'boot-ls nil)
67+
(-let (((&hash "command" "arguments") params))
68+
(setf (nth 2 arguments) (if (nth 2 arguments) t :json-false))
69+
(lsp-request "workspace/executeCommand"
70+
(list :command command :arguments arguments)
71+
:no-wait t))))
72+
73+
(defun lsp-java-boot--lens-backend (_ callback)
74+
"Boot backend.
75+
Store CALLBACK to use it `sts/highlight'."
76+
(setq-local lsp-java-boot--callback callback))
77+
78+
;;;###autoload
79+
(define-minor-mode lsp-java-boot-lens-mode
80+
"Toggle code-lens overlays."
81+
:group 'lsp-java-boot
82+
:global nil
83+
:init-value nil
84+
:lighter "BLens"
85+
(cond
86+
(lsp-java-boot-lens-mode
87+
(setq-local lsp-lens-backends (pushnew 'lsp-java-boot--lens-backend lsp-lens-backends))
88+
(lsp--lens-refresh t))
89+
(t (setq-local lsp-lens-backends (delete 'lsp-java-boot--lens-backend lsp-lens-backends))
90+
(setq-local lsp-java-boot--callback nil))))
91+
92+
(cl-defmethod lsp-execute-command
93+
(server (command (eql sts.open.url)) params)
94+
(browse-url (first params)))
95+
96+
(cl-defmethod lsp-execute-command (server (command (eql sts.showHoverAtPosition)) params)
97+
(goto-char (lsp--position-to-point (first params)))
98+
(lsp-describe-thing-at-point))
99+
100+
(defun lsp-java-boot--sts/hightlight (workspace params)
101+
"WORKSPACE PARAMS."
102+
(with-lsp-workspace workspace
103+
(-let (((&hash "doc" (&hash "uri" "version") "codeLenses" code-lenses) params))
104+
(when-let (buf (find-buffer-visiting (lsp--uri-to-path uri)))
105+
(with-current-buffer buf
106+
(when (and lsp-java-boot--callback lsp-java-boot-lens-mode)
107+
(funcall lsp-java-boot--callback code-lenses version)))))))
108+
109+
(defun lsp-java-boot--server-jar ()
110+
"Return the spring boot jar."
111+
(or (-> lsp-java-server-install-dir
112+
(expand-file-name)
113+
(f-join "boot-server")
114+
f-files
115+
first)
116+
(lsp-log "Unable to find spring boot server jar.")))
117+
118+
(defun lsp-java-boot--ls-command (port)
119+
"Create LS command for PORT."
120+
(list lsp-java-java-path
121+
(format "-Dloader.path=%s" (lsp-java-boot--find-tools-jar))
122+
(format "-Dspring.lsp.client-port=%s" port)
123+
(format "-Dserver.port=%s" port)
124+
"-Dsts.lsp.client=vscode"
125+
(concat "-Dsts.log.file=" (make-temp-file "sts-log-file" nil ".log"))
126+
(concat "-Dlogging.file=" (make-temp-file "logging-file" nil ".log"))
127+
"-jar"
128+
(lsp-java-boot--server-jar)))
129+
130+
(lsp-register-client
131+
(make-lsp-client :new-connection
132+
(lsp-tcp-server #'lsp-java-boot--ls-command)
133+
:activation-fn (lambda (filename major-mode)
134+
(and lsp-java-boot-enabled
135+
(memq major-mode '(java-mode conf-javaprop-mode yaml-mode))
136+
(lsp-java-boot--server-jar)))
137+
:request-handlers (ht ("sts/addClasspathListener" #'lsp-java-boot--sts-add-classpath-listener)
138+
("sts/javadocHoverLink" #'lsp-java--sts-javadoc-hover-link))
139+
:notification-handlers (ht ("sts/highlight" #'lsp-java-boot--sts/hightlight)
140+
("sts/progress" #'ignore))
141+
:initialized-fn (lambda (workspace)
142+
(puthash
143+
"triggerCharacters"
144+
'("." "@" "#" "*")
145+
(gethash "completionProvider" (lsp--workspace-server-capabilities workspace))))
146+
:multi-root t
147+
:add-on? t
148+
:server-id 'boot-ls))
149+
150+
(provide 'lsp-java-boot)
151+
;;; lsp-java-boot.el ends here

0 commit comments

Comments
 (0)