Skip to content

Commit 0fb7e7d

Browse files
committed
Minimal Spring Factories support in Boot LS
1 parent 4618a07 commit 0fb7e7d

File tree

10 files changed

+243
-3
lines changed

10 files changed

+243
-3
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<projectDescription>
3+
<name>org.springframework.boot.ide.product.e417</name>
4+
<comment></comment>
5+
<projects>
6+
</projects>
7+
<buildSpec>
8+
<buildCommand>
9+
<name>org.eclipse.m2e.core.maven2Builder</name>
10+
<arguments>
11+
</arguments>
12+
</buildCommand>
13+
</buildSpec>
14+
<natures>
15+
<nature>org.eclipse.m2e.core.maven2Nature</nature>
16+
</natures>
17+
</projectDescription>

eclipse-language-servers/org.springframework.tooling.boot.ls/plugin.xml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@
3434
id="org.eclipse.languageserver.languages.springboot">
3535
</contentTypeMapping>
3636

37+
<contentTypeMapping
38+
contentType="org.springframework.boot.ide.boot.factories"
39+
id="org.eclipse.languageserver.languages.springboot"
40+
languageId="spring-factories">
41+
</contentTypeMapping>
42+
3743
</extension>
3844

3945
<extension
@@ -86,6 +92,16 @@
8692
priority="high">
8793
</content-type>
8894

95+
<content-type
96+
base-type="org.eclipse.core.runtime.text"
97+
default-charset="UTF-8"
98+
file-names="spring.factories,aot.factories"
99+
file-patterns="*.factories"
100+
id="org.springframework.boot.ide.boot.factories"
101+
name="Spring Factories File"
102+
priority="high">
103+
</content-type>
104+
89105
<content-type
90106
base-type="org.eclipse.core.runtime.xml"
91107
default-charset="UTF-8"
@@ -109,6 +125,11 @@
109125
file-patterns="application-*.yml,application-*.yaml">
110126
</file-association>
111127

128+
<file-association
129+
content-type="org.springframework.boot.ide.boot.factories"
130+
file-names="spring.factories,aot.factories"
131+
file-patterns="*.factories">
132+
</file-association>
112133
</extension>
113134

114135
<extension
@@ -269,6 +290,21 @@
269290
</editor>
270291
</extension>
271292

293+
<extension
294+
point="org.eclipse.ui.editors">
295+
<editor
296+
class="org.eclipse.ui.internal.genericeditor.ExtensionBasedTextEditor"
297+
contributorClass="org.eclipse.ui.editors.text.TextEditorActionContributor"
298+
icon="icons/spring_obj.gif"
299+
id="SpringFactoriesEditor"
300+
name="Generic Editor - Spring Factories"
301+
symbolicFontName="org.eclipse.jdt.ui.PropertiesFileEditor.textfont">
302+
<contentTypeBinding
303+
contentTypeId="org.springframework.boot.ide.boot.factories"
304+
/>
305+
</editor>
306+
</extension>
307+
272308
<extension
273309
point="org.eclipse.ui.genericeditor.presentationReconcilers">
274310
<presentationReconciler
@@ -285,6 +321,14 @@
285321
</presentationReconciler>
286322
</extension>
287323

324+
<extension
325+
point="org.eclipse.ui.genericeditor.presentationReconcilers">
326+
<presentationReconciler
327+
class="org.eclipse.tm4e.ui.text.TMPresentationReconciler"
328+
contentType="org.springframework.boot.ide.boot.factories">
329+
</presentationReconciler>
330+
</extension>
331+
288332
<extension
289333
point="org.eclipse.tm4e.registry.grammars">
290334
<grammar
@@ -309,6 +353,13 @@
309353
</scopeNameContentTypeBinding>
310354
</extension>
311355

356+
<extension
357+
point="org.eclipse.tm4e.registry.grammars">
358+
<scopeNameContentTypeBinding
359+
contentTypeId="org.springframework.boot.ide.boot.factories"
360+
scopeName="source.java-properties">
361+
</scopeNameContentTypeBinding>
362+
</extension>
312363

313364
<extension
314365
id="springxml-completion-computer"

headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/ListenerList.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public synchronized void fire(T evt) {
3333
}
3434
}
3535

36-
public void add(Consumer<T> l) {
36+
public synchronized void add(Consumer<T> l) {
3737
listeners.add(l);
3838
}
3939

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerInitializer.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
package org.springframework.ide.vscode.boot.app;
1212

1313
import java.net.URI;
14-
import java.nio.file.Path;
1514
import java.time.Duration;
1615
import java.util.ArrayList;
1716
import java.util.HashMap;
@@ -28,6 +27,7 @@
2827
import org.springframework.beans.factory.annotation.Qualifier;
2928
import org.springframework.context.ApplicationContext;
3029
import org.springframework.ide.vscode.boot.common.IJavaProjectReconcileEngine;
30+
import org.springframework.ide.vscode.boot.factories.SpringFactoriesLanguageServerComponents;
3131
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents;
3232
import org.springframework.ide.vscode.boot.java.links.JavaElementLocationProvider;
3333
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
@@ -143,6 +143,7 @@ public void afterPropertiesSet() throws Exception {
143143
BootJavaLanguageServerComponents bootJavaLanguageServerComponent = new BootJavaLanguageServerComponents(appContext);
144144
builder.add(bootJavaLanguageServerComponent);
145145
builder.add(new SpringXMLLanguageServerComponents(server, springIndexer, params, config));
146+
builder.add(new SpringFactoriesLanguageServerComponents(projectFinder, springIndexer));
146147
components = builder.build(server);
147148

148149
projectReconciler = (IJavaProjectReconcileEngine) bootJavaLanguageServerComponent.getReconcileEngine().get();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2022 VMware, Inc.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* https://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* VMware, Inc. - initial API and implementation
10+
*******************************************************************************/
11+
package org.springframework.ide.vscode.boot.factories;
12+
13+
import java.util.Optional;
14+
import java.util.Set;
15+
16+
import org.springframework.ide.vscode.boot.app.SpringSymbolIndex;
17+
import org.springframework.ide.vscode.commons.languageserver.composable.LanguageServerComponents;
18+
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
19+
import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcileEngine;
20+
import org.springframework.ide.vscode.commons.languageserver.util.DocumentSymbolHandler;
21+
import org.springframework.ide.vscode.commons.languageserver.util.HoverHandler;
22+
import org.springframework.ide.vscode.commons.util.text.LanguageId;
23+
24+
public class SpringFactoriesLanguageServerComponents implements LanguageServerComponents {
25+
26+
private SpringFactoriesReconcileEngine reconciler;
27+
private SpringSymbolIndex springIndex;
28+
29+
public SpringFactoriesLanguageServerComponents(JavaProjectFinder projectFinder, SpringSymbolIndex springIndex) {
30+
this.springIndex = springIndex;
31+
reconciler = new SpringFactoriesReconcileEngine(projectFinder);
32+
}
33+
34+
@Override
35+
public Set<LanguageId> getInterestingLanguages() {
36+
return Set.of(LanguageId.SPRING_FACTORIES);
37+
}
38+
39+
@Override
40+
public HoverHandler getHoverProvider() {
41+
return null;
42+
}
43+
44+
@Override
45+
public Optional<IReconcileEngine> getReconcileEngine() {
46+
return Optional.of(reconciler);
47+
}
48+
49+
@Override
50+
public Optional<DocumentSymbolHandler> getDocumentSymbolProvider() {
51+
return Optional.of(params -> springIndex.getSymbols(params.getTextDocument().getUri()));
52+
}
53+
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package org.springframework.ide.vscode.boot.factories;
2+
3+
/*******************************************************************************
4+
* Copyright (c) 2022 VMware, Inc.
5+
* All rights reserved. This program and the accompanying materials
6+
* are made available under the terms of the Eclipse Public License v1.0
7+
* which accompanies this distribution, and is available at
8+
* https://www.eclipse.org/legal/epl-v10.html
9+
*
10+
* Contributors:
11+
* VMware, Inc. - initial API and implementation
12+
*******************************************************************************/
13+
import java.util.Map;
14+
15+
import org.eclipse.lsp4j.TextDocumentIdentifier;
16+
import org.springframework.ide.vscode.boot.java.Boot3JavaProblemType;
17+
import org.springframework.ide.vscode.commons.java.IJavaProject;
18+
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
19+
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
20+
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
21+
import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcileEngine;
22+
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl;
23+
import org.springframework.ide.vscode.commons.util.text.IDocument;
24+
import org.springframework.ide.vscode.java.properties.antlr.parser.AntlrParser;
25+
import org.springframework.ide.vscode.java.properties.parser.PropertiesAst;
26+
import org.springframework.ide.vscode.java.properties.parser.PropertiesAst.KeyValuePair;
27+
28+
public class SpringFactoriesReconcileEngine implements IReconcileEngine {
29+
30+
@FunctionalInterface
31+
interface KeyValuePairReconciler {
32+
void reconcile(IJavaProject project, KeyValuePair pair, IProblemCollector problemCollector);
33+
}
34+
35+
private final JavaProjectFinder projectFinder;
36+
private AntlrParser parser = new AntlrParser();
37+
38+
private final Map<String, KeyValuePairReconciler> keyValuePairReconcilers = Map.of(
39+
"org.springframework.boot.autoconfigure.EnableAutoConfiguration", (project, pair, problemCollector) -> {
40+
if (SpringProjectUtil.springBootVersionGreaterOrEqual(3, 0, 0).test(project)) {
41+
ReconcileProblemImpl problem = new ReconcileProblemImpl(
42+
Boot3JavaProblemType.FACTORIES_KEY_NOT_SUPPORTED,
43+
"Key is not supported as of Spring Boot 3. See Boot 3 documentation topic \"Locating Auto-configuration Candidates\"",
44+
pair.getOffset(),
45+
pair.getLength());
46+
problemCollector.accept(problem);
47+
}
48+
}
49+
);
50+
51+
public SpringFactoriesReconcileEngine(JavaProjectFinder projectFinder) {
52+
this.projectFinder = projectFinder;
53+
}
54+
55+
@Override
56+
public void reconcile(IDocument doc, IProblemCollector problemCollector) {
57+
projectFinder.find(new TextDocumentIdentifier(doc.getUri())).ifPresent(project -> {
58+
problemCollector.beginCollecting();
59+
try {
60+
PropertiesAst ast = parser.parse(doc.get()).ast;
61+
if (ast != null) {
62+
for (KeyValuePair pair : ast.getNodes(KeyValuePair.class)) {
63+
String key = pair.getKey().decode().trim();
64+
KeyValuePairReconciler r = keyValuePairReconcilers.get(key);
65+
if (r != null) {
66+
r.reconcile(project, pair, problemCollector);
67+
}
68+
}
69+
}
70+
} finally {
71+
problemCollector.endCollecting();
72+
}
73+
});
74+
}
75+
76+
}

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/Boot3JavaProblemType.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ public enum Boot3JavaProblemType implements ProblemType {
3030

3131
JAVA_BEAN_NOT_REGISTERED_IN_AOT(WARNING, "Not registered as Bean", "Not registered as a Bean"),
3232

33-
JAVA_TYPE_NOT_SUPPORTED(ERROR, "Type no supported as of Spring Boot 3", "Type not supported as of Spring Boot 3");
33+
JAVA_TYPE_NOT_SUPPORTED(ERROR, "Type no supported as of Spring Boot 3", "Type not supported as of Spring Boot 3"),
34+
35+
FACTORIES_KEY_NOT_SUPPORTED(ERROR, "Spring factories key not supported", "Spring factories key not supported");
3436

3537
private final ProblemSeverity defaultSeverity;
3638
private String description;

headless-services/spring-boot-language-server/src/main/resources/problem-types.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@
7272
"label": "Type not supported as of Spring Boot 3",
7373
"description": "Type no supported as of Spring Boot 3",
7474
"defaultSeverity": "ERROR"
75+
},
76+
{
77+
"code": "FACTORIES_KEY_NOT_SUPPORTED",
78+
"label": "Spring factories key not supported",
79+
"description": "Spring factories key not supported",
80+
"defaultSeverity": "ERROR"
7581
}
7682
]
7783
},

vscode-extensions/vscode-spring-boot/lib/Main.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const PROPERTIES_LANGUAGE_ID = "spring-boot-properties";
1616
const YAML_LANGUAGE_ID = "spring-boot-properties-yaml";
1717
const JAVA_LANGUAGE_ID = "java";
1818
const XML_LANGUAGE_ID = "xml";
19+
const FACTORIES_LANGUAGE_ID = "spring-factories";
1920

2021
const NEVER_SHOW_AGAIN = "Do not show again";
2122

@@ -93,6 +94,10 @@ export function activate(context: VSCode.ExtensionContext): Thenable<ExtensionAP
9394
{
9495
language: XML_LANGUAGE_ID,
9596
scheme: 'file'
97+
},
98+
{
99+
language: FACTORIES_LANGUAGE_ID,
100+
scheme: 'file'
96101
}
97102
],
98103
synchronize: {

vscode-extensions/vscode-spring-boot/package.json

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"onLanguage:spring-boot-properties-yaml",
3131
"onLanguage:java",
3232
"onLanguage:xml",
33+
"onLanguage:spring-factories",
3334
"onDebugResolve:java",
3435
"onCommand:vscode-spring-boot.rewrite.list"
3536
],
@@ -64,6 +65,16 @@
6465
"bootstrap*.properties"
6566
],
6667
"configuration": "./properties-support/language-configuration.json"
68+
},
69+
{
70+
"id": "spring-factories",
71+
"aliases": [
72+
"Spring Factories"
73+
],
74+
"filenamePatterns": [
75+
"*.factories"
76+
],
77+
"configuration": "./properties-support/language-configuration.json"
6778
}
6879
],
6980
"menus": {
@@ -390,6 +401,18 @@
390401
"HINT",
391402
"ERROR"
392403
]
404+
},
405+
"spring-boot.ls.problem.boot3.FACTORIES_KEY_NOT_SUPPORTED": {
406+
"type": "string",
407+
"default": "ERROR",
408+
"description": "Spring factories key not supported",
409+
"enum": [
410+
"IGNORE",
411+
"INFO",
412+
"WARNING",
413+
"HINT",
414+
"ERROR"
415+
]
393416
}
394417
}
395418
},
@@ -734,6 +757,11 @@
734757
"language": "spring-boot-properties",
735758
"scopeName": "source.java-properties",
736759
"path": "./properties-support/java-properties.tmLanguage"
760+
},
761+
{
762+
"language": "spring-factories",
763+
"scopeName": "source.java-properties",
764+
"path": "./properties-support/java-properties.tmLanguage"
737765
}
738766
]
739767
},

0 commit comments

Comments
 (0)