From cd0eebcc15f07b34f8572c059d7687ae52fc2270 Mon Sep 17 00:00:00 2001 From: Kris De Volder Date: Fri, 2 Oct 2020 17:45:36 -0700 Subject: [PATCH] Boot Language Server obeys configured problem severities --- .../BootValidationPreferencesPage.java | 2 + ...bstractProblemSeverityPreferencesPage.java | 3 + .../boot/ls/BootLanguageServerPlugin.java | 2 +- .../DelegatingStreamConnectionProvider.java | 42 +++++++++++++ ...pertiesEditorProblemSeverityPrefsPage.java | 3 +- ...ionYamlEditorProblemSeverityPrefsPage.java | 3 +- .../reconcile/DiagnosticSeverityProvider.java | 13 ++-- .../reconcile/ReconcileProblemImpl.java | 4 ++ .../commons/languageserver/util/Settings.java | 35 ++++++++++- .../ide/vscode/boot/app/BootJavaConfig.java | 7 ++- .../boot/app/ProblemSeverityConfigurer.java | 63 +++++++++++++++++++ .../reconcile/SpringPropertyProblem.java | 2 +- 12 files changed, 166 insertions(+), 13 deletions(-) create mode 100644 headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/ProblemSeverityConfigurer.java diff --git a/eclipse-extensions/org.springframework.ide.eclipse.boot.validation/src/org/springframework/ide/eclipse/boot/validation/preferences/BootValidationPreferencesPage.java b/eclipse-extensions/org.springframework.ide.eclipse.boot.validation/src/org/springframework/ide/eclipse/boot/validation/preferences/BootValidationPreferencesPage.java index 89516b521..667bbf570 100644 --- a/eclipse-extensions/org.springframework.ide.eclipse.boot.validation/src/org/springframework/ide/eclipse/boot/validation/preferences/BootValidationPreferencesPage.java +++ b/eclipse-extensions/org.springframework.ide.eclipse.boot.validation/src/org/springframework/ide/eclipse/boot/validation/preferences/BootValidationPreferencesPage.java @@ -12,6 +12,7 @@ package org.springframework.ide.eclipse.boot.validation.preferences; import java.util.List; +import org.eclipse.ui.plugin.AbstractUIPlugin; import org.springframework.ide.eclipse.boot.validation.BootValidationActivator; import org.springframework.ide.eclipse.boot.validation.rules.BootValidationProblemType; import org.springframework.ide.eclipse.editor.support.preferences.AbstractProblemSeverityPreferencesPage; @@ -45,4 +46,5 @@ public class BootValidationPreferencesPage extends AbstractProblemSeverityPrefer return BootValidationActivator.PLUGIN_ID; } + } diff --git a/eclipse-extensions/org.springframework.ide.eclipse.editor.support/src/org/springframework/ide/eclipse/editor/support/preferences/AbstractProblemSeverityPreferencesPage.java b/eclipse-extensions/org.springframework.ide.eclipse.editor.support/src/org/springframework/ide/eclipse/editor/support/preferences/AbstractProblemSeverityPreferencesPage.java index 12c8723de..e64400600 100644 --- a/eclipse-extensions/org.springframework.ide.eclipse.editor.support/src/org/springframework/ide/eclipse/editor/support/preferences/AbstractProblemSeverityPreferencesPage.java +++ b/eclipse-extensions/org.springframework.ide.eclipse.editor.support/src/org/springframework/ide/eclipse/editor/support/preferences/AbstractProblemSeverityPreferencesPage.java @@ -19,11 +19,13 @@ import java.util.List; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ProjectScope; import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.preferences.DefaultScope; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.jface.dialogs.ControlEnableState; import org.eclipse.jface.preference.ComboFieldEditor; +import org.eclipse.jface.preference.FieldEditor; import org.eclipse.jface.preference.FieldEditorPreferencePage; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.swt.SWT; @@ -33,6 +35,7 @@ import org.eclipse.swt.widgets.Control; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPreferencePage; import org.eclipse.ui.IWorkbenchPropertyPage; +import org.eclipse.ui.plugin.AbstractUIPlugin; import org.eclipse.ui.preferences.ScopedPreferenceStore; import org.osgi.service.prefs.BackingStoreException; import org.springframework.ide.eclipse.boot.util.Log; diff --git a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/BootLanguageServerPlugin.java b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/BootLanguageServerPlugin.java index 4527565fd..880dfd773 100644 --- a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/BootLanguageServerPlugin.java +++ b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/BootLanguageServerPlugin.java @@ -30,7 +30,7 @@ import org.osgi.framework.BundleContext; */ public class BootLanguageServerPlugin extends AbstractUIPlugin { - public static final String PLUGIN_ID = "org.springframework.tooling.boot.java.ls"; + public static String PLUGIN_ID = "org.springframework.tooling.boot.ls"; private static final Object LSP4E_COMMAND_SYMBOL_IN_WORKSPACE = "org.eclipse.lsp4e.symbolinworkspace"; diff --git a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/DelegatingStreamConnectionProvider.java b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/DelegatingStreamConnectionProvider.java index 85e534707..45d87c903 100644 --- a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/DelegatingStreamConnectionProvider.java +++ b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/DelegatingStreamConnectionProvider.java @@ -23,6 +23,7 @@ import java.util.Map; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.lsp4e.server.StreamConnectionProvider; @@ -35,6 +36,7 @@ import org.springframework.tooling.ls.eclipse.commons.LanguageServerCommonsActiv import org.springsource.ide.eclipse.commons.boot.ls.remoteapps.RemoteBootAppsDataHolder; import org.springsource.ide.eclipse.commons.boot.ls.remoteapps.RemoteBootAppsDataHolder.RemoteAppData; import org.springsource.ide.eclipse.commons.livexp.core.ValueListener; +import org.springsource.ide.eclipse.commons.livexp.util.Log; import com.google.common.collect.ImmutableSet; @@ -64,6 +66,7 @@ public class DelegatingStreamConnectionProvider implements StreamConnectionProvi private LanguageServer languageServer; private final IPropertyChangeListener configListener = (e) -> sendConfiguration(); + private final ValueListener> remoteAppsListener = (e, v) -> sendConfiguration(); private long timestampBeforeStart; @@ -117,6 +120,7 @@ public class DelegatingStreamConnectionProvider implements StreamConnectionProvi fResourceListener = null; } BootLanguageServerPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(configListener); +// BootLanguageServerPlugin.getPreferences().removePreferenceChangeListener(prefsListener); RemoteBootAppsDataHolder.getDefault().getRemoteApps().removeListener(remoteAppsListener); } @@ -134,6 +138,7 @@ public class DelegatingStreamConnectionProvider implements StreamConnectionProvi // Add config listener BootLanguageServerPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(configListener); +// BootLanguageServerPlugin.getPreferences().addPreferenceChangeListener(prefsListener); // Add resource listener ResourcesPlugin.getWorkspace().addResourceChangeListener(fResourceListener = new ResourceListener(languageServer, Arrays.asList( @@ -194,9 +199,46 @@ public class DelegatingStreamConnectionProvider implements StreamConnectionProvi bootJavaObj.put("validation", validation); bootJavaObj.put("remote-apps", getAllRemoteApps()); settings.put("boot-java", bootJavaObj); + + putValidationPreferences(settings); this.languageServer.getWorkspaceService().didChangeConfiguration(new DidChangeConfigurationParams(settings)); } + + private void putValidationPreferences(Map settings) { + try { + IEclipsePreferences prefs = BootLanguageServerPlugin.getPreferences(); + for (String key : prefs.keys()) { + if (key.startsWith("problem.")) { + String val = prefs.get(key, null); + if (val!=null) { + dotPut(settings, "spring-boot.ls."+key, val); + } + } + } + } catch (Exception e) { + Log.log(e); + } + } + + private void dotPut(Object _settings, String dottedProperty, Object value) { + if (_settings instanceof Map) { + Map settings = (Map) _settings; + int dot = dottedProperty.indexOf('.'); + if (dot>=0) { + String first = dottedProperty.substring(0, dot); + String rest = dottedProperty.substring(dot+1); + Object nested = settings.getOrDefault(first, null); + if (nested==null) { + nested = new HashMap<>(); + settings.put(first, nested); + } + dotPut(nested, rest, value); + } else { + settings.put(dottedProperty, value); + } + } + } /** * Combines remote boot app data from all configuration sources. diff --git a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/prefs/ApplicationPropertiesEditorProblemSeverityPrefsPage.java b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/prefs/ApplicationPropertiesEditorProblemSeverityPrefsPage.java index f3d10d623..d2ba1a41d 100644 --- a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/prefs/ApplicationPropertiesEditorProblemSeverityPrefsPage.java +++ b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/prefs/ApplicationPropertiesEditorProblemSeverityPrefsPage.java @@ -12,13 +12,14 @@ package org.springframework.tooling.boot.ls.prefs; import java.io.IOException; +import org.eclipse.ui.plugin.AbstractUIPlugin; import org.springframework.ide.eclipse.editor.support.preferences.ProblemSeverityPreferencesUtil; import org.springframework.ide.eclipse.editor.support.preferences.ProblemSeverityPreferityPageFromMetadata; import org.springframework.tooling.boot.ls.BootLanguageServerPlugin; public class ApplicationPropertiesEditorProblemSeverityPrefsPage extends ProblemSeverityPreferityPageFromMetadata { - public static final ProblemSeverityPreferencesUtil util = new ProblemSeverityPreferencesUtil("application.properties.problem."); + public static final ProblemSeverityPreferencesUtil util = new ProblemSeverityPreferencesUtil("problem.properties."); public ApplicationPropertiesEditorProblemSeverityPrefsPage() throws IOException { super(util, LanguageServerProblemTypesMetadata.load().get("application-properties")); diff --git a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/prefs/ApplicationYamlEditorProblemSeverityPrefsPage.java b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/prefs/ApplicationYamlEditorProblemSeverityPrefsPage.java index 30e47a6f4..2922e8413 100644 --- a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/prefs/ApplicationYamlEditorProblemSeverityPrefsPage.java +++ b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/prefs/ApplicationYamlEditorProblemSeverityPrefsPage.java @@ -18,7 +18,7 @@ import org.springframework.tooling.boot.ls.BootLanguageServerPlugin; public class ApplicationYamlEditorProblemSeverityPrefsPage extends ProblemSeverityPreferityPageFromMetadata { - public static final ProblemSeverityPreferencesUtil util = new ProblemSeverityPreferencesUtil("application.yaml.problem."); + public static final ProblemSeverityPreferencesUtil util = new ProblemSeverityPreferencesUtil("problem.yaml."); public ApplicationYamlEditorProblemSeverityPrefsPage() throws IOException { super(util, LanguageServerProblemTypesMetadata.load().get("application-yaml")); @@ -28,5 +28,4 @@ public class ApplicationYamlEditorProblemSeverityPrefsPage extends ProblemSeveri protected String getPluginId() { return BootLanguageServerPlugin.PLUGIN_ID; } - } diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/DiagnosticSeverityProvider.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/DiagnosticSeverityProvider.java index 1343c537f..c0503c0dc 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/DiagnosticSeverityProvider.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/DiagnosticSeverityProvider.java @@ -14,10 +14,8 @@ import org.eclipse.lsp4j.DiagnosticSeverity; @FunctionalInterface public interface DiagnosticSeverityProvider { - DiagnosticSeverity getDiagnosticSeverity(ReconcileProblem problem); - - static final DiagnosticSeverityProvider DEFAULT = (problem) -> { - ProblemSeverity severity = problem.getType().getDefaultSeverity(); + + static DiagnosticSeverity diagnosticSeverity(ProblemSeverity severity) { switch (severity) { case ERROR: return DiagnosticSeverity.Error; @@ -32,5 +30,12 @@ public interface DiagnosticSeverityProvider { default: throw new IllegalStateException("Bug! Missing switch case?"); } + } + + DiagnosticSeverity getDiagnosticSeverity(ReconcileProblem problem); + + static final DiagnosticSeverityProvider DEFAULT = (problem) -> { + ProblemSeverity severity = problem.getType().getDefaultSeverity(); + return diagnosticSeverity(severity); }; } diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/ReconcileProblemImpl.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/ReconcileProblemImpl.java index 79ffda0cf..0421ffe5d 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/ReconcileProblemImpl.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/reconcile/ReconcileProblemImpl.java @@ -93,4 +93,8 @@ public class ReconcileProblemImpl implements ReconcileProblem { return this; } + @Override + public String toString() { + return this.getClass().getSimpleName()+"("+type+", "+msg+")"; + } } diff --git a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/Settings.java b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/Settings.java index b13e22e97..a6fb4c6e9 100644 --- a/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/Settings.java +++ b/headless-services/commons/commons-language-server/src/main/java/org/springframework/ide/vscode/commons/languageserver/util/Settings.java @@ -15,10 +15,12 @@ import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonElement; +import com.google.gson.JsonNull; import com.google.gson.JsonObject; /** @@ -129,7 +131,38 @@ public class Settings { @Override public String toString() { - return settings.toString(); + return ""+settings; + } + + public Settings navigate(String... names) { + if (this.settings!=null && !this.settings.isJsonNull()) { + if (names.length==0) { + return this; + } else if (this.settings.isJsonObject()) { + JsonObject obj = (JsonObject) this.settings; + if (obj.has(names[0])) { + Settings sub = new Settings(obj.get(names[0])); + return sub.navigate(cdr(names)); + } + } + } + return new Settings(JsonNull.INSTANCE); + } + + private String[] cdr(String[] names) { + String[] rest = new String[names.length-1]; + for (int i = 0; i < rest.length; i++) { + rest[i] = names[i+1]; + } + return rest; + } + + public Iterable keys() { + if (settings!=null && settings.isJsonObject()) { + JsonObject obj = (JsonObject) settings; + return obj.keySet(); + } + return ImmutableList.of(); } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootJavaConfig.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootJavaConfig.java index df732ea3c..6730e5259 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootJavaConfig.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootJavaConfig.java @@ -39,9 +39,6 @@ public class BootJavaConfig implements InitializingBean { public static final boolean VALIDAITON_SPEL_EXPRESSIONS_ENABLED_DEFAULT = true; - //TODO: Consider changing this to something that raises Spring application events. - // I.e. like described in here: https://www.baeldung.com/spring-events - private final SimpleWorkspaceService workspace; private Settings settings = new Settings(null); private ListenerList listeners = new ListenerList(); @@ -140,4 +137,8 @@ public class BootJavaConfig implements InitializingBean { public void afterPropertiesSet() throws Exception { workspace.onDidChangeConfiguraton(this::handleConfigurationChange); } + + public Settings getRawSettings() { + return settings; + } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/ProblemSeverityConfigurer.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/ProblemSeverityConfigurer.java new file mode 100644 index 000000000..a4a11738f --- /dev/null +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/ProblemSeverityConfigurer.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2020 Pivotal, 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: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.boot.app; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.ide.vscode.commons.languageserver.reconcile.DiagnosticSeverityProvider; +import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemSeverity; +import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem; +import org.springframework.ide.vscode.commons.languageserver.util.Settings; +import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; +import org.springframework.ide.vscode.commons.util.Assert; +import org.springframework.stereotype.Component; + +@Component +public class ProblemSeverityConfigurer implements InitializingBean { + + @Autowired + private SimpleLanguageServer server; + + @Autowired + private BootJavaConfig config; + + @Override + public void afterPropertiesSet() throws Exception { + config.addListener((x) -> configChanged()); + configChanged(); + } + + private void configChanged() { + Settings settings = config.getRawSettings(); + settings = settings.navigate("spring-boot", "ls", "problem"); + + Map severityOverrides = new HashMap<>(); + for (String editorType : settings.keys()) { + Settings problemConf = settings.navigate(editorType); + for (String code : problemConf.keys()) { + String severity = problemConf.getString(code); + System.out.println(code+" => "+severity); + Assert.isLegal(!severityOverrides.containsKey(code), "Multpile entries for problem type "+code); + severityOverrides.put(code, ProblemSeverity.valueOf(severity)); + } + } + server.setDiagnosticSeverityProvider((ReconcileProblem problem) -> { + ProblemSeverity severity = severityOverrides.get(problem.getType().getCode()); + if (severity==null) { + severity = problem.getType().getDefaultSeverity(); + } + return DiagnosticSeverityProvider.diagnosticSeverity(severity); + }); + } +} diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/reconcile/SpringPropertyProblem.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/reconcile/SpringPropertyProblem.java index dd337ba98..4f6c492fb 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/reconcile/SpringPropertyProblem.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/properties/reconcile/SpringPropertyProblem.java @@ -45,5 +45,5 @@ public class SpringPropertyProblem extends ReconcileProblemImpl { public void setPropertyName(String name) { propertyName = name; } - + }