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 3ccf028e5..652813a0a 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018, 2022 Pivotal, Inc. + * Copyright (c) 2018, 2023 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 @@ -11,9 +11,9 @@ package org.springframework.ide.vscode.boot.app; import java.net.URI; +import java.nio.file.Path; +import java.nio.file.Paths; import java.time.Duration; -import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -38,6 +38,7 @@ import org.springframework.ide.vscode.boot.java.utils.SymbolCache; import org.springframework.ide.vscode.boot.metadata.ProjectBasedPropertyIndexProvider; import org.springframework.ide.vscode.boot.properties.BootPropertiesLanguageServerComponents; import org.springframework.ide.vscode.boot.xml.SpringXMLLanguageServerComponents; +import org.springframework.ide.vscode.commons.java.IClasspathUtil; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.completion.CompositeCompletionEngine; import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine; @@ -262,26 +263,19 @@ public class BootLanguageServerInitializer implements InitializingBean { } components.getReconcileEngine().ifPresent(reconcileEngine -> { - Map> projectsToDocs = new HashMap<>(); for (String f : files) { URI uri = URI.create(f); TextDocumentIdentifier docId = new TextDocumentIdentifier(uri.toString()); TextDocument doc = server.getTextDocumentService().getLatestSnapshot(docId.getUri()); if (doc == null) { projectFinder.find(docId).ifPresent(project -> { - List docIds = projectsToDocs.get(project); - if (docIds == null) { - docIds = new ArrayList<>(); - projectsToDocs.put(project, docIds); + Path p = Paths.get(uri); + if (IClasspathUtil.getSourceFolders(project.getClasspath()).filter(folder -> p.startsWith(folder.toPath())).findFirst().isPresent()) { + validateProject(project, reconcileEngine); } - docIds.add(docId); }); } } - - for (IJavaProject p : projectsToDocs.keySet()) { - validateProject(p, reconcileEngine); - } }); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootVersionValidationEngine.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootVersionValidationEngine.java index 26144cd79..1e02fb19b 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootVersionValidationEngine.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootVersionValidationEngine.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022 VMware, Inc. + * Copyright (c) 2022, 2023 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 @@ -41,7 +41,7 @@ public class BootVersionValidationEngine { @Override public void changed(IJavaProject project) { - + validate(project); } }); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServerComponents.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServerComponents.java index 8da574cc3..7b47cd5f6 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServerComponents.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServerComponents.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016, 2022 Pivotal, Inc. + * Copyright (c) 2016, 2023 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 @@ -188,7 +188,7 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent highlightsEngine = createDocumentHighlightEngine(indexer); documents.onDocumentHighlight(highlightsEngine); - JdtReconciler jdtReconciler = new JdtReconciler(cuCache); + JdtReconciler jdtReconciler = new JdtReconciler(cuCache, config); RewriteCompilationUnitCache orCompilationUnitCache = appContext.getBean(RewriteCompilationUnitCache.class); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/JdtReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/JdtReconciler.java index 9783ad81c..2a41df595 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/JdtReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/JdtReconciler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022 VMware, Inc. + * Copyright (c) 2022, 2023 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 @@ -26,6 +26,7 @@ import org.eclipse.jdt.core.dom.NormalAnnotation; import org.eclipse.jdt.core.dom.SingleMemberAnnotation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.ide.vscode.boot.app.BootJavaConfig; import org.springframework.ide.vscode.boot.java.handlers.SpelExpressionReconciler; import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache; import org.springframework.ide.vscode.boot.java.value.Constants; @@ -55,9 +56,12 @@ public class JdtReconciler implements JavaReconciler { private final CompilationUnitCache compilationUnitCache; private final AnnotationReconciler[] reconcilers; private final SpelExpressionReconciler spelExpressionReconciler; + + private BootJavaConfig config; - public JdtReconciler(CompilationUnitCache compilationUnitCache) { - this.compilationUnitCache = compilationUnitCache; + public JdtReconciler(CompilationUnitCache compilationUnitCache, BootJavaConfig config) { + this.compilationUnitCache = compilationUnitCache; + this.config = config; this.spelExpressionReconciler = new SpelExpressionReconciler(); this.reconcilers = new AnnotationReconciler[] { @@ -95,7 +99,6 @@ public class JdtReconciler implements JavaReconciler { @Override public void reconcile(IJavaProject project, final IDocument doc, final IProblemCollector problemCollector) { - log.info("reconciling (JDT): " + project.getElementName() + " - " + doc.getUri()); long start = System.currentTimeMillis(); URI uri = URI.create(doc.getUri()); @@ -107,7 +110,7 @@ public class JdtReconciler implements JavaReconciler { }); long end = System.currentTimeMillis(); - log.info("reconciling (JDT): " + project.getElementName() + " done in " + (end - start) + "ms"); + log.info("reconciling (JDT): " + doc.getUri() + " done in " + (end - start) + "ms"); } private void reconcileAST(IJavaProject project, IDocument doc, CompilationUnit cu, IProblemCollector problemCollector) { @@ -159,7 +162,15 @@ public class JdtReconciler implements JavaReconciler { @Override public Map> reconcile(IJavaProject project, List docs, Function problemCollectorFactory) { - log.info("reconciling (JDT, multiple docs): " + project.getElementName() + " - " + docs.size()); + + if (config.isRewriteReconcileEnabled()) { +// long start = System.currentTimeMillis(); +// +// +// +// long end = System.currentTimeMillis(); +// log.info("reconciling project (JDT): " + project.getElementName() + " - " + docs.size() + " done in " + (end - start) + "ms"); + } return Collections.emptyMap(); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/RewriteCompilationUnitCache.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/RewriteCompilationUnitCache.java index 2fd9cbcc4..265aa34c3 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/RewriteCompilationUnitCache.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/RewriteCompilationUnitCache.java @@ -61,8 +61,8 @@ public class RewriteCompilationUnitCache implements DocumentContentProvider, Dis private final SimpleTextDocumentService documentService; private final Cache> uriToCu; - private final Cache> projectToDocs; - private final Cache javaParsers; + private final Cache> projectToDocs; + private final Cache javaParsers; public RewriteCompilationUnitCache(JavaProjectFinder projectFinder, SimpleLanguageServer server, ProjectObserver projectObserver) { // this.projectFinder = projectFinder; @@ -87,11 +87,10 @@ public class RewriteCompilationUnitCache implements DocumentContentProvider, Dis Optional project = projectFinder.find(new TextDocumentIdentifier(uri.toString())); if (project.isPresent()) { - JavaParser parser = javaParsers.getIfPresent(project.get()); + JavaParser parser = javaParsers.getIfPresent(project.get().getLocationUri()); if (parser != null) { parser.reset(); } -// javaParsers.invalidate(project.get()); } } } @@ -155,7 +154,7 @@ public class RewriteCompilationUnitCache implements DocumentContentProvider, Dis private JavaParser loadJavaParser(IJavaProject project) { try { - return javaParsers.get(project, () -> ORAstUtils.createJavaParser(project)); + return javaParsers.get(project.getLocationUri(), () -> ORAstUtils.createJavaParser(project)); } catch (ExecutionException e) { logger.error("{}", e); return null; @@ -170,12 +169,12 @@ public class RewriteCompilationUnitCache implements DocumentContentProvider, Dis private void invalidateProject(IJavaProject project) { logger.info("CU Cache: invalidate project <{}>", project.getElementName()); - Set docUris = projectToDocs.getIfPresent(project); + Set docUris = projectToDocs.getIfPresent(project.getLocationUri()); if (docUris != null) { uriToCu.invalidateAll(docUris); - projectToDocs.invalidate(project); + projectToDocs.invalidate(project.getLocationUri()); } - javaParsers.invalidate(project); + javaParsers.invalidate(project.getLocationUri()); } @Override @@ -240,7 +239,7 @@ public class RewriteCompilationUnitCache implements DocumentContentProvider, Dis CompilationUnit cu = cus.get(0); if (cu != null) { - projectToDocs.get(project, () -> new HashSet<>()).add(uri); + projectToDocs.get(project.getLocationUri(), () -> new HashSet<>()).add(uri); return cu; } else { throw new IllegalStateException("Failed to parse Java source"); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/RewriteReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/RewriteReconciler.java index a86f740cd..bf3e052a2 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/RewriteReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/rewrite/RewriteReconciler.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022 VMware, Inc. + * Copyright (c) 2022, 2023 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 @@ -79,7 +79,6 @@ public class RewriteReconciler implements JavaReconciler { return; } - log.info("reconciling (OpenRewrite): " + project.getElementName() + " - " + doc.getUri()); long start = System.currentTimeMillis(); try { @@ -104,7 +103,7 @@ public class RewriteReconciler implements JavaReconciler { } long end = System.currentTimeMillis(); - log.info("reconciling (OpenRewrite): " + project.getElementName() + " done in " + (end - start) + "ms"); + log.info("reconciling (OpenRewrite): " + doc.getUri() + " done in " + (end - start) + "ms"); } private List createProblems(IDocument doc, FixAssistMarker m, J astNode) { @@ -143,7 +142,10 @@ public class RewriteReconciler implements JavaReconciler { public Map> reconcile(IJavaProject project, List docs, Function problemCollectorFactory) { - log.info("reconciling (OpenRewrite, multiple docs): " + project.getElementName() + " - " + docs.size()); + if (!config.isRewriteReconcileEnabled()) { + return Collections.emptyMap(); + } + long start = System.currentTimeMillis(); Map> allProblems = new HashMap<>(); @@ -165,7 +167,7 @@ public class RewriteReconciler implements JavaReconciler { allProblems.putAll(doReconcile(project, testSources, problemCollectorFactory, javaParser)); long end = System.currentTimeMillis(); - log.info("reconciling (OpenRewrite, multiple docs): " + project.getElementName() + " - " + docs.size() + " done in " + (end - start) + "ms"); + log.info("reconciling project (OpenRewrite): " + project.getElementName() + " - " + docs.size() + " done in " + (end - start) + "ms"); return allProblems; } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/CompilationUnitCache.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/CompilationUnitCache.java index 3b12da415..290bb05b0 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/CompilationUnitCache.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/CompilationUnitCache.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2022 Pivotal, Inc. + * Copyright (c) 2017, 2023 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 @@ -68,8 +68,8 @@ public final class CompilationUnitCache implements DocumentContentProvider { private final SimpleTextDocumentService documentService; private final Cache> uriToCu; - private final Cache> projectToDocs; - private final Cache, INameEnvironmentWithProgress>> lookupEnvCache; + private final Cache> projectToDocs; + private final Cache, INameEnvironmentWithProgress>> lookupEnvCache; public CompilationUnitCache(JavaProjectFinder projectFinder, SimpleLanguageServer server, ProjectObserver projectObserver) { this.projectFinder = projectFinder; @@ -224,7 +224,7 @@ public final class CompilationUnitCache implements DocumentContentProvider { if (cu != null) { try { - projectToDocs.get(project, () -> new HashSet<>()).add(uri); + projectToDocs.get(project.getLocationUri(), () -> new HashSet<>()).add(uri); logger.debug("CU Cache: start work on AST for {}", uri.toString()); return requestor.apply(cu); @@ -287,7 +287,7 @@ public final class CompilationUnitCache implements DocumentContentProvider { private Tuple2, INameEnvironmentWithProgress> loadLookupEnvTuple(IJavaProject project) { try { - return lookupEnvCache.get(project, () -> { + return lookupEnvCache.get(project.getLocationUri(), () -> { List classpaths = createClasspath(getClasspathEntries(project)); INameEnvironmentWithProgress environment = CUResolver.createLookupEnvironment(classpaths.toArray(new Classpath[classpaths.size()])); return Tuples.of(classpaths, environment); @@ -320,12 +320,12 @@ public final class CompilationUnitCache implements DocumentContentProvider { private void invalidateProject(IJavaProject project) { logger.debug("CU Cache: invalidate project <{}>", project.getElementName()); - Set docUris = projectToDocs.getIfPresent(project); + Set docUris = projectToDocs.getIfPresent(project.getLocationUri()); if (docUris != null) { uriToCu.invalidateAll(docUris); - projectToDocs.invalidate(project); + projectToDocs.invalidate(project.getLocationUri()); } - lookupEnvCache.invalidate(project); + lookupEnvCache.invalidate(project.getLocationUri()); } @Override diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringLiveChangeDetectionWatchdog.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringLiveChangeDetectionWatchdog.java index 7d94d891d..31c440a9b 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringLiveChangeDetectionWatchdog.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringLiveChangeDetectionWatchdog.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018, 2019 Pivotal, Inc. + * Copyright (c) 2018, 2023 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 @@ -10,6 +10,7 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.utils; +import java.net.URI; import java.time.Duration; import java.util.HashSet; import java.util.Set; @@ -41,7 +42,7 @@ public class SpringLiveChangeDetectionWatchdog { private final SourceLinks sourceLinks; private final ChangeDetectionHistory changeHistory; - private final Set observedProjects; + private final Set observedProjects; private boolean changeDetectionEnabled = false; private ScheduledThreadPoolExecutor timer; @@ -54,7 +55,7 @@ public class SpringLiveChangeDetectionWatchdog { Duration pollingInterval, SourceLinks sourceLinks ) { - this.observedProjects = new HashSet<>(); + this.observedProjects = new HashSet(); this.server = server; @@ -68,12 +69,12 @@ public class SpringLiveChangeDetectionWatchdog { @Override public void deleted(IJavaProject project) { - observedProjects.remove(project); + observedProjects.remove(project.getLocationUri()); } @Override public void created(IJavaProject project) { - observedProjects.add(project); + observedProjects.add(project.getLocationUri()); } @Override diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/jdt/ls/JdtLsProjectCache.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/jdt/ls/JdtLsProjectCache.java index 1aaf68cf4..6812cdca6 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/jdt/ls/JdtLsProjectCache.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/jdt/ls/JdtLsProjectCache.java @@ -350,15 +350,19 @@ public class JdtLsProjectCache implements InitializableJavaProjectsService, Serv log.debug("deleted = false"); URI projectUri = new URI(uri); ClasspathData classpath = new ClasspathData(event.name, event.classpath.getEntries()); - IProjectBuild projectBuild = from(event.projectBuild); + IJavaProject oldProject = table.get(uri); + if (oldProject != null && classpath.equals(oldProject.getClasspath())) { + // nothing has changed + return; + } + IProjectBuild projectBuild = from(event.projectBuild); IJavaProject newProject = IS_JANDEX_INDEX ? new JavaProject(getFileObserver(), projectUri, classpath, JdtLsProjectCache.this, projectBuild) : new JdtLsJavaProject(server.getClient(), projectUri, classpath, JdtLsProjectCache.this, projectBuild); - IJavaProject oldProject = table.put(uri, newProject); + table.put(uri, newProject); if (oldProject != null) { - notifyDelete(oldProject); - notifyCreated(newProject); + notifyChanged(newProject); } else { notifyCreated(newProject); } diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/ValueSpelExpressionValidationTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/ValueSpelExpressionValidationTest.java index a518b3567..0f04b15e3 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/ValueSpelExpressionValidationTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/ValueSpelExpressionValidationTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2020, 2022 Pivotal, Inc. + * Copyright (c) 2020, 2023 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 @@ -35,6 +35,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.ide.vscode.boot.app.BootJavaConfig; import org.springframework.ide.vscode.boot.app.BootLanguageServerParams; import org.springframework.ide.vscode.boot.bootiful.AdHocPropertyHarnessTestConf; import org.springframework.ide.vscode.boot.bootiful.BootLanguageServerTest; @@ -75,6 +76,7 @@ public class ValueSpelExpressionValidationTest { @Autowired private JavaProjectFinder projectFinder; @Autowired private CompilationUnitCache compilationUnitCache; @Autowired private SimpleLanguageServer server; + @Autowired private BootJavaConfig config; private File directory; private String docUri; @@ -146,7 +148,7 @@ public class ValueSpelExpressionValidationTest { problemCollector = new TestProblemCollector(); reconcileEngine = new BootJavaReconcileEngine(projectFinder, new JavaReconciler[] { - new JdtReconciler(compilationUnitCache) + new JdtReconciler(compilationUnitCache, config) }, server.getTextDocumentService(), null); }