Minimal Spring Factories support in Boot LS

This commit is contained in:
aboyko
2022-10-20 10:15:29 -04:00
parent 4618a07968
commit 0fb7e7daca
10 changed files with 243 additions and 3 deletions

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.springframework.boot.ide.product.e417</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

View File

@@ -34,6 +34,12 @@
id="org.eclipse.languageserver.languages.springboot">
</contentTypeMapping>
<contentTypeMapping
contentType="org.springframework.boot.ide.boot.factories"
id="org.eclipse.languageserver.languages.springboot"
languageId="spring-factories">
</contentTypeMapping>
</extension>
<extension
@@ -86,6 +92,16 @@
priority="high">
</content-type>
<content-type
base-type="org.eclipse.core.runtime.text"
default-charset="UTF-8"
file-names="spring.factories,aot.factories"
file-patterns="*.factories"
id="org.springframework.boot.ide.boot.factories"
name="Spring Factories File"
priority="high">
</content-type>
<content-type
base-type="org.eclipse.core.runtime.xml"
default-charset="UTF-8"
@@ -109,6 +125,11 @@
file-patterns="application-*.yml,application-*.yaml">
</file-association>
<file-association
content-type="org.springframework.boot.ide.boot.factories"
file-names="spring.factories,aot.factories"
file-patterns="*.factories">
</file-association>
</extension>
<extension
@@ -269,6 +290,21 @@
</editor>
</extension>
<extension
point="org.eclipse.ui.editors">
<editor
class="org.eclipse.ui.internal.genericeditor.ExtensionBasedTextEditor"
contributorClass="org.eclipse.ui.editors.text.TextEditorActionContributor"
icon="icons/spring_obj.gif"
id="SpringFactoriesEditor"
name="Generic Editor - Spring Factories"
symbolicFontName="org.eclipse.jdt.ui.PropertiesFileEditor.textfont">
<contentTypeBinding
contentTypeId="org.springframework.boot.ide.boot.factories"
/>
</editor>
</extension>
<extension
point="org.eclipse.ui.genericeditor.presentationReconcilers">
<presentationReconciler
@@ -285,6 +321,14 @@
</presentationReconciler>
</extension>
<extension
point="org.eclipse.ui.genericeditor.presentationReconcilers">
<presentationReconciler
class="org.eclipse.tm4e.ui.text.TMPresentationReconciler"
contentType="org.springframework.boot.ide.boot.factories">
</presentationReconciler>
</extension>
<extension
point="org.eclipse.tm4e.registry.grammars">
<grammar
@@ -309,6 +353,13 @@
</scopeNameContentTypeBinding>
</extension>
<extension
point="org.eclipse.tm4e.registry.grammars">
<scopeNameContentTypeBinding
contentTypeId="org.springframework.boot.ide.boot.factories"
scopeName="source.java-properties">
</scopeNameContentTypeBinding>
</extension>
<extension
id="springxml-completion-computer"

View File

@@ -33,7 +33,7 @@ public class ListenerList<T> {
}
}
public void add(Consumer<T> l) {
public synchronized void add(Consumer<T> l) {
listeners.add(l);
}

View File

@@ -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();

View File

@@ -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<LanguageId> getInterestingLanguages() {
return Set.of(LanguageId.SPRING_FACTORIES);
}
@Override
public HoverHandler getHoverProvider() {
return null;
}
@Override
public Optional<IReconcileEngine> getReconcileEngine() {
return Optional.of(reconciler);
}
@Override
public Optional<DocumentSymbolHandler> getDocumentSymbolProvider() {
return Optional.of(params -> springIndex.getSymbols(params.getTextDocument().getUri()));
}
}

View File

@@ -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<String, KeyValuePairReconciler> 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();
}
});
}
}

View File

@@ -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;

View File

@@ -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"
}
]
},

View File

@@ -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<ExtensionAP
{
language: XML_LANGUAGE_ID,
scheme: 'file'
},
{
language: FACTORIES_LANGUAGE_ID,
scheme: 'file'
}
],
synchronize: {

View File

@@ -30,6 +30,7 @@
"onLanguage:spring-boot-properties-yaml",
"onLanguage:java",
"onLanguage:xml",
"onLanguage:spring-factories",
"onDebugResolve:java",
"onCommand:vscode-spring-boot.rewrite.list"
],
@@ -64,6 +65,16 @@
"bootstrap*.properties"
],
"configuration": "./properties-support/language-configuration.json"
},
{
"id": "spring-factories",
"aliases": [
"Spring Factories"
],
"filenamePatterns": [
"*.factories"
],
"configuration": "./properties-support/language-configuration.json"
}
],
"menus": {
@@ -390,6 +401,18 @@
"HINT",
"ERROR"
]
},
"spring-boot.ls.problem.boot3.FACTORIES_KEY_NOT_SUPPORTED": {
"type": "string",
"default": "ERROR",
"description": "Spring factories key not supported",
"enum": [
"IGNORE",
"INFO",
"WARNING",
"HINT",
"ERROR"
]
}
}
},
@@ -734,6 +757,11 @@
"language": "spring-boot-properties",
"scopeName": "source.java-properties",
"path": "./properties-support/java-properties.tmLanguage"
},
{
"language": "spring-factories",
"scopeName": "source.java-properties",
"path": "./properties-support/java-properties.tmLanguage"
}
]
},