diff --git a/eclipse-distribution/org.springframework.boot.ide.product.e417/.project b/eclipse-distribution/org.springframework.boot.ide.product.e417/.project
new file mode 100644
index 000000000..bee6e73c3
--- /dev/null
+++ b/eclipse-distribution/org.springframework.boot.ide.product.e417/.project
@@ -0,0 +1,17 @@
+
+
+ org.springframework.boot.ide.product.e417
+
+
+
+
+
+ org.eclipse.m2e.core.maven2Builder
+
+
+
+
+
+ org.eclipse.m2e.core.maven2Nature
+
+
diff --git a/eclipse-language-servers/org.springframework.tooling.boot.ls/plugin.xml b/eclipse-language-servers/org.springframework.tooling.boot.ls/plugin.xml
index c8396672a..90c842288 100644
--- a/eclipse-language-servers/org.springframework.tooling.boot.ls/plugin.xml
+++ b/eclipse-language-servers/org.springframework.tooling.boot.ls/plugin.xml
@@ -34,6 +34,12 @@
id="org.eclipse.languageserver.languages.springboot">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{
}
}
- public void add(Consumer l) {
+ public synchronized void add(Consumer l) {
listeners.add(l);
}
diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerInitializer.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerInitializer.java
index 3bdc86c30..187ebba19 100644
--- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerInitializer.java
+++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerInitializer.java
@@ -11,7 +11,6 @@
package org.springframework.ide.vscode.boot.app;
import java.net.URI;
-import java.nio.file.Path;
import java.time.Duration;
import java.util.ArrayList;
import java.util.HashMap;
@@ -28,6 +27,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.ide.vscode.boot.common.IJavaProjectReconcileEngine;
+import org.springframework.ide.vscode.boot.factories.SpringFactoriesLanguageServerComponents;
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents;
import org.springframework.ide.vscode.boot.java.links.JavaElementLocationProvider;
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
@@ -143,6 +143,7 @@ public class BootLanguageServerInitializer implements InitializingBean {
BootJavaLanguageServerComponents bootJavaLanguageServerComponent = new BootJavaLanguageServerComponents(appContext);
builder.add(bootJavaLanguageServerComponent);
builder.add(new SpringXMLLanguageServerComponents(server, springIndexer, params, config));
+ builder.add(new SpringFactoriesLanguageServerComponents(projectFinder, springIndexer));
components = builder.build(server);
projectReconciler = (IJavaProjectReconcileEngine) bootJavaLanguageServerComponent.getReconcileEngine().get();
diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/factories/SpringFactoriesLanguageServerComponents.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/factories/SpringFactoriesLanguageServerComponents.java
new file mode 100644
index 000000000..21b7bee84
--- /dev/null
+++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/factories/SpringFactoriesLanguageServerComponents.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2022 VMware, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.springframework.ide.vscode.boot.factories;
+
+import java.util.Optional;
+import java.util.Set;
+
+import org.springframework.ide.vscode.boot.app.SpringSymbolIndex;
+import org.springframework.ide.vscode.commons.languageserver.composable.LanguageServerComponents;
+import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
+import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcileEngine;
+import org.springframework.ide.vscode.commons.languageserver.util.DocumentSymbolHandler;
+import org.springframework.ide.vscode.commons.languageserver.util.HoverHandler;
+import org.springframework.ide.vscode.commons.util.text.LanguageId;
+
+public class SpringFactoriesLanguageServerComponents implements LanguageServerComponents {
+
+ private SpringFactoriesReconcileEngine reconciler;
+ private SpringSymbolIndex springIndex;
+
+ public SpringFactoriesLanguageServerComponents(JavaProjectFinder projectFinder, SpringSymbolIndex springIndex) {
+ this.springIndex = springIndex;
+ reconciler = new SpringFactoriesReconcileEngine(projectFinder);
+ }
+
+ @Override
+ public Set getInterestingLanguages() {
+ return Set.of(LanguageId.SPRING_FACTORIES);
+ }
+
+ @Override
+ public HoverHandler getHoverProvider() {
+ return null;
+ }
+
+ @Override
+ public Optional getReconcileEngine() {
+ return Optional.of(reconciler);
+ }
+
+ @Override
+ public Optional getDocumentSymbolProvider() {
+ return Optional.of(params -> springIndex.getSymbols(params.getTextDocument().getUri()));
+ }
+
+}
diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/factories/SpringFactoriesReconcileEngine.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/factories/SpringFactoriesReconcileEngine.java
new file mode 100644
index 000000000..5c223330a
--- /dev/null
+++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/factories/SpringFactoriesReconcileEngine.java
@@ -0,0 +1,76 @@
+package org.springframework.ide.vscode.boot.factories;
+
+/*******************************************************************************
+ * Copyright (c) 2022 VMware, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VMware, Inc. - initial API and implementation
+ *******************************************************************************/
+import java.util.Map;
+
+import org.eclipse.lsp4j.TextDocumentIdentifier;
+import org.springframework.ide.vscode.boot.java.Boot3JavaProblemType;
+import org.springframework.ide.vscode.commons.java.IJavaProject;
+import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
+import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
+import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
+import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcileEngine;
+import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl;
+import org.springframework.ide.vscode.commons.util.text.IDocument;
+import org.springframework.ide.vscode.java.properties.antlr.parser.AntlrParser;
+import org.springframework.ide.vscode.java.properties.parser.PropertiesAst;
+import org.springframework.ide.vscode.java.properties.parser.PropertiesAst.KeyValuePair;
+
+public class SpringFactoriesReconcileEngine implements IReconcileEngine {
+
+ @FunctionalInterface
+ interface KeyValuePairReconciler {
+ void reconcile(IJavaProject project, KeyValuePair pair, IProblemCollector problemCollector);
+ }
+
+ private final JavaProjectFinder projectFinder;
+ private AntlrParser parser = new AntlrParser();
+
+ private final Map keyValuePairReconcilers = Map.of(
+ "org.springframework.boot.autoconfigure.EnableAutoConfiguration", (project, pair, problemCollector) -> {
+ if (SpringProjectUtil.springBootVersionGreaterOrEqual(3, 0, 0).test(project)) {
+ ReconcileProblemImpl problem = new ReconcileProblemImpl(
+ Boot3JavaProblemType.FACTORIES_KEY_NOT_SUPPORTED,
+ "Key is not supported as of Spring Boot 3. See Boot 3 documentation topic \"Locating Auto-configuration Candidates\"",
+ pair.getOffset(),
+ pair.getLength());
+ problemCollector.accept(problem);
+ }
+ }
+ );
+
+ public SpringFactoriesReconcileEngine(JavaProjectFinder projectFinder) {
+ this.projectFinder = projectFinder;
+ }
+
+ @Override
+ public void reconcile(IDocument doc, IProblemCollector problemCollector) {
+ projectFinder.find(new TextDocumentIdentifier(doc.getUri())).ifPresent(project -> {
+ problemCollector.beginCollecting();
+ try {
+ PropertiesAst ast = parser.parse(doc.get()).ast;
+ if (ast != null) {
+ for (KeyValuePair pair : ast.getNodes(KeyValuePair.class)) {
+ String key = pair.getKey().decode().trim();
+ KeyValuePairReconciler r = keyValuePairReconcilers.get(key);
+ if (r != null) {
+ r.reconcile(project, pair, problemCollector);
+ }
+ }
+ }
+ } finally {
+ problemCollector.endCollecting();
+ }
+ });
+ }
+
+}
diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/Boot3JavaProblemType.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/Boot3JavaProblemType.java
index df35790d6..0726e2233 100644
--- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/Boot3JavaProblemType.java
+++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/Boot3JavaProblemType.java
@@ -30,7 +30,9 @@ public enum Boot3JavaProblemType implements ProblemType {
JAVA_BEAN_NOT_REGISTERED_IN_AOT(WARNING, "Not registered as Bean", "Not registered as a Bean"),
- JAVA_TYPE_NOT_SUPPORTED(ERROR, "Type no supported as of Spring Boot 3", "Type not supported as of Spring Boot 3");
+ JAVA_TYPE_NOT_SUPPORTED(ERROR, "Type no supported as of Spring Boot 3", "Type not supported as of Spring Boot 3"),
+
+ FACTORIES_KEY_NOT_SUPPORTED(ERROR, "Spring factories key not supported", "Spring factories key not supported");
private final ProblemSeverity defaultSeverity;
private String description;
diff --git a/headless-services/spring-boot-language-server/src/main/resources/problem-types.json b/headless-services/spring-boot-language-server/src/main/resources/problem-types.json
index 00c2091a6..56269efca 100644
--- a/headless-services/spring-boot-language-server/src/main/resources/problem-types.json
+++ b/headless-services/spring-boot-language-server/src/main/resources/problem-types.json
@@ -72,6 +72,12 @@
"label": "Type not supported as of Spring Boot 3",
"description": "Type no supported as of Spring Boot 3",
"defaultSeverity": "ERROR"
+ },
+ {
+ "code": "FACTORIES_KEY_NOT_SUPPORTED",
+ "label": "Spring factories key not supported",
+ "description": "Spring factories key not supported",
+ "defaultSeverity": "ERROR"
}
]
},
diff --git a/vscode-extensions/vscode-spring-boot/lib/Main.ts b/vscode-extensions/vscode-spring-boot/lib/Main.ts
index 3c2f3ff8b..34a5cfb8f 100644
--- a/vscode-extensions/vscode-spring-boot/lib/Main.ts
+++ b/vscode-extensions/vscode-spring-boot/lib/Main.ts
@@ -16,6 +16,7 @@ const PROPERTIES_LANGUAGE_ID = "spring-boot-properties";
const YAML_LANGUAGE_ID = "spring-boot-properties-yaml";
const JAVA_LANGUAGE_ID = "java";
const XML_LANGUAGE_ID = "xml";
+const FACTORIES_LANGUAGE_ID = "spring-factories";
const NEVER_SHOW_AGAIN = "Do not show again";
@@ -93,6 +94,10 @@ export function activate(context: VSCode.ExtensionContext): Thenable