Start Boot LS if classpath of any project has spring

This commit is contained in:
aboyko
2022-11-10 15:48:43 -05:00
parent 6a9969d3ff
commit df0d85cef7
19 changed files with 499 additions and 32 deletions

View File

@@ -35,7 +35,8 @@ Require-Bundle: org.eclipse.jdt.launching;bundle-version="3.9.0",
org.springframework.ide.eclipse.editor.support,
com.google.guava,
org.eclipse.core.expressions,
org.springsource.ide.eclipse.commons.core;bundle-version="4.17.0"
org.springsource.ide.eclipse.commons.core;bundle-version="4.17.0",
org.springframework.tooling.jdt.ls.commons;bundle-version="4.17.0"
Import-Package: com.google.common.base,
com.google.common.collect,
com.google.gson;version="2.7.0",

View File

@@ -9,35 +9,75 @@
clientImpl="org.springframework.tooling.ls.eclipse.commons.STS4LanguageClientImpl"
id="org.eclipse.languageserver.languages.springboot"
label="Spring Boot Language Server"
lastDocumentDisconnectedTimeout="10">
lastDocumentDisconnectedTimeout="2147483647">
</server>
<contentTypeMapping
contentType="org.eclipse.jdt.core.javaSource"
id="org.eclipse.languageserver.languages.springboot">
<!--
<enabledInputWhen
description="Resource belongs to a project with Spring Boot on Classpath">
<test
property="org.springframework.tooling.boot.isBootResource">
</test>
</enabledInputWhen>
-->
</contentTypeMapping>
<contentTypeMapping
contentType="org.springframework.boot.ide.properties.application.properties"
id="org.eclipse.languageserver.languages.springboot"
languageId="spring-boot-properties">
<!--
<enabledInputWhen
description="Resource belongs to a project with Spring Boot on Classpath">
<test
property="org.springframework.tooling.boot.isBootResource">
</test>
</enabledInputWhen>
-->
</contentTypeMapping>
<contentTypeMapping
contentType="org.springframework.boot.ide.properties.application.yml"
id="org.eclipse.languageserver.languages.springboot"
languageId="spring-boot-properties-yaml">
<!--
<enabledInputWhen
description="Resource belongs to a project with Spring Boot on Classpath">
<test
property="org.springframework.tooling.boot.isBootResource">
</test>
</enabledInputWhen>
-->
</contentTypeMapping>
<contentTypeMapping
contentType="org.springframework.boot.ide.xmlconfig"
id="org.eclipse.languageserver.languages.springboot">
<!--
<enabledInputWhen
description="Resource belongs to a project with Spring Boot on Classpath">
<test
property="org.springframework.tooling.boot.isBootResource">
</test>
</enabledInputWhen>
-->
</contentTypeMapping>
<contentTypeMapping
contentType="org.springframework.boot.ide.boot.factories"
id="org.eclipse.languageserver.languages.springboot"
languageId="spring-factories">
<!--
<enabledInputWhen
description="Resource belongs to a project with Spring Boot on Classpath">
<test
property="org.springframework.tooling.boot.isBootResource">
</test>
</enabledInputWhen>
-->
</contentTypeMapping>
</extension>
@@ -493,6 +533,19 @@
properties="areRewriteProjectRefactoringsOn"
type="java.lang.Object">
</propertyTester>
<propertyTester
class="org.springframework.tooling.boot.ls.BootProjectTester"
id="org.springframework.tooling.boot"
namespace="org.springframework.tooling.boot"
properties="isBootResource"
type="java.lang.Object">
</propertyTester>
</extension>
<extension
point="org.eclipse.ui.startup">
<startup
class="org.springframework.tooling.boot.ls.Startup">
</startup>
</extension>
<!--
<extension

View File

@@ -81,6 +81,7 @@ public class BootJavaPreferencesPage extends FieldEditorPreferencePage implement
Composite fieldEditorParent = getFieldEditorParent();
addField(new BooleanFieldEditor(Constants.PREF_START_LS_EARLY, "Start Language Server at startup if Spring Boot is a dependency", fieldEditorParent));
addField(new BooleanFieldEditor(Constants.PREF_SCAN_JAVA_TEST_SOURCES, "Scan Java test sources", fieldEditorParent));
addField(new StringFieldEditor(Constants.PREF_LIVE_INFORMATION_FETCH_DATA_RETRY_MAX_NO, "Live Information - Max number of retries (before giving up)", fieldEditorParent));

View File

@@ -0,0 +1,90 @@
/*******************************************************************************
* 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.tooling.boot.ls;
import org.eclipse.core.expressions.PropertyTester;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jface.text.IDocument;
import org.eclipse.lsp4e.LSPEclipseUtils;
import org.springsource.ide.eclipse.commons.internal.core.CorePlugin;
@SuppressWarnings("restriction")
public class BootProjectTester extends PropertyTester {
@Override
public boolean test(Object receiver, String property, Object[] args, Object expectedValue) {
if ("isBootResource".equals(property)) {
IResource resource = null;
if (receiver instanceof IAdaptable) {
resource = ((IAdaptable) receiver).getAdapter(IResource.class);
} else if (receiver instanceof IDocument) {
resource = LSPEclipseUtils.getFile((IDocument) receiver);
}
if (resource != null) {
IProject project = resource.getProject();
if (project != null) {
IJavaProject jp = JavaCore.create(project);
if (jp != null) {
return isBootProject(project);
}
}
}
}
return false;
}
private static boolean isBootProject(IProject project) {
if (project==null || ! project.isAccessible()) {
return false;
}
try {
if (project.hasNature(JavaCore.NATURE_ID)) {
IJavaProject jp = JavaCore.create(project);
IClasspathEntry[] classpath = jp.getResolvedClasspath(true);
//Look for a 'spring-boot' jar or project entry
for (IClasspathEntry e : classpath) {
if (isBootJar(e) || isBootProject(e)) {
return true;
}
}
}
} catch (Exception e) {
CorePlugin.log(e);
}
return false;
}
private static boolean isBootJar(IClasspathEntry e) {
if (e.getEntryKind()==IClasspathEntry.CPE_LIBRARY) {
IPath path = e.getPath();
String name = path.lastSegment();
return name.endsWith(".jar") && name.startsWith("spring-boot");
}
return false;
}
private static boolean isBootProject(IClasspathEntry e) {
if (e.getEntryKind()==IClasspathEntry.CPE_PROJECT) {
IPath path = e.getPath();
String name = path.lastSegment();
return name.startsWith("spring-boot");
}
return false;
}
}

View File

@@ -40,4 +40,6 @@ public class Constants {
public static final String PREF_REWRITE_RECIPES_SCAN_DIRS = "boot-java.rewrite.scan-directories";
public static final String PREF_REWRITE_PROJECT_REFACTORINGS = "boot-java.rewrite.project-refactorings";
public static final String PREF_START_LS_EARLY = "start.boot-ls.early";
}

View File

@@ -18,6 +18,7 @@ import java.nio.file.FileSystems;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.ResourcesPlugin;
@@ -60,7 +61,12 @@ public class DelegatingStreamConnectionProvider implements StreamConnectionProvi
private ResourceListener fResourceListener;
private LanguageServer languageServer;
private final IPropertyChangeListener configListener = (e) -> sendConfiguration();
private static final List<String> PREFS_EXCLUSIONS = List.of(Constants.PREF_START_LS_EARLY);
private final IPropertyChangeListener configListener = (e) -> {
if (!PREFS_EXCLUSIONS.contains(e.getProperty())) {
sendConfiguration();
}
};
private final ValueListener<ImmutableSet<RemoteAppData>> remoteAppsListener = (e, v) -> sendConfiguration();

View File

@@ -28,6 +28,8 @@ public class PrefsInitializer extends AbstractPreferenceInitializer {
@Override
public void initializeDefaultPreferences() {
IPreferenceStore preferenceStore = BootLanguageServerPlugin.getDefault().getPreferenceStore();
preferenceStore.setDefault(Constants.PREF_START_LS_EARLY, true);
preferenceStore.setDefault(Constants.PREF_LIVE_INFORMATION_FETCH_DATA_RETRY_MAX_NO, 10);
preferenceStore.setDefault(Constants.PREF_LIVE_INFORMATION_FETCH_DATA_RETRY_DELAY_IN_SECONDS, 3);

View File

@@ -0,0 +1,60 @@
/*******************************************************************************
* 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.tooling.boot.ls;
import java.io.IOException;
import java.util.List;
import org.eclipse.lsp4e.LanguageServerWrapper;
import org.eclipse.lsp4e.LanguageServersRegistry;
import org.eclipse.lsp4e.LanguageServersRegistry.LanguageServerDefinition;
import org.eclipse.lsp4e.LanguageServiceAccessor;
import org.eclipse.ui.IStartup;
import org.springframework.tooling.jdt.ls.commons.BootProjectTracker;
import org.springframework.tooling.jdt.ls.commons.Logger;
@SuppressWarnings("restriction")
public class Startup implements IStartup {
private static final String BOOT_LS_DEFINITION_ID = "org.eclipse.languageserver.languages.springboot";
private LanguageServerWrapper lsWrapper = null;
@Override
public void earlyStartup() {
if (BootLanguageServerPlugin.getDefault().getPreferenceStore().getBoolean(Constants.PREF_START_LS_EARLY)) {
new BootProjectTracker(Logger.forEclipsePlugin(() -> BootLanguageServerPlugin.getDefault()),
List.of(springProjects -> {
if (springProjects.isEmpty()) {
if (lsWrapper != null) {
lsWrapper.stop();
lsWrapper = null;
}
} else {
if (lsWrapper == null) {
LanguageServerDefinition serverDefinition = LanguageServersRegistry.getInstance()
.getDefinition(BOOT_LS_DEFINITION_ID);
try {
lsWrapper = LanguageServiceAccessor.getLSWrapper(
springProjects.iterator().next().getProject(), serverDefinition);
lsWrapper.start();
} catch (IOException e1) {
BootLanguageServerPlugin.getDefault().getLog()
.error("Failed to launch Boot Language Server", e1);
}
}
}
}));
}
}
}