diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/SpringSymbolIndex.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/SpringSymbolIndex.java index 5ccc75a24..9ba36f71b 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/SpringSymbolIndex.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/SpringSymbolIndex.java @@ -387,28 +387,29 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex { log.debug("Project with NULL name is being initialized"); return CompletableFuture.completedFuture(null); } else { + synchronized(this) { // synchronized since the `indexers` array can change via a settings change + @SuppressWarnings("unchecked") + CompletableFuture[] futures = new CompletableFuture[this.indexers.length + 1]; - @SuppressWarnings("unchecked") - CompletableFuture[] futures = new CompletableFuture[this.indexers.length + 1]; + // clean future + futures[0] = CompletableFuture.runAsync(() -> { + removeSymbolsByProject(project); + springIndex.removeBeans(project.getElementName()); + }, this.updateQueue); + + // index futures + for (int i = 0; i < this.indexers.length; i++) { + InitializeProject initializeItem = new InitializeProject(project, this.indexers[i], clean); + futures[i + 1] = CompletableFuture.runAsync(initializeItem, this.updateQueue); + } + + CompletableFuture future = CompletableFuture.allOf(futures); + + future = future.thenAccept(v -> server.getClient().indexUpdated()).thenAccept(v -> listeners.fire(v)); - // clean future - futures[0] = CompletableFuture.runAsync(() -> { - removeSymbolsByProject(project); - springIndex.removeBeans(project.getElementName()); - }, this.updateQueue); - - // index futures - for (int i = 0; i < this.indexers.length; i++) { - InitializeProject initializeItem = new InitializeProject(project, this.indexers[i], clean); - futures[i + 1] = CompletableFuture.runAsync(initializeItem, this.updateQueue); + this.latestScheduledTaskByProject.put(project.getElementName(), future); + return future; } - - CompletableFuture future = CompletableFuture.allOf(futures); - - future = future.thenAccept(v -> server.getClient().indexUpdated()).thenAccept(v -> listeners.fire(v)); - - this.latestScheduledTaskByProject.put(project.getElementName(), future); - return future; } } else { return deleteProject(project); @@ -715,15 +716,17 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex { ImmutableList.Builder builder = ImmutableList.builder(); if (project != null && doc != null) { // Collect symbols from the opened document - for (SpringIndexer indexer : this.indexers) { - if (indexer.isInterestedIn(docURI)) { - try { - for (EnhancedSymbolInformation enhanced : indexer.computeSymbols(project, docURI, - doc.get())) { - builder.add(enhanced.getSymbol()); + synchronized(this) { + for (SpringIndexer indexer : this.indexers) { + if (indexer.isInterestedIn(docURI)) { + try { + for (EnhancedSymbolInformation enhanced : indexer.computeSymbols(project, docURI, + doc.get())) { + builder.add(enhanced.getSymbol()); + } + } catch (Exception e) { + log.error("{}", e); } - } catch (Exception e) { - log.error("{}", e); } } } diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/xml/test/XMLBeanRefContentAssistTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/xml/test/XMLBeanRefContentAssistTest.java index f13987d32..79cd027fd 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/xml/test/XMLBeanRefContentAssistTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/xml/test/XMLBeanRefContentAssistTest.java @@ -73,6 +73,8 @@ public class XMLBeanRefContentAssistTest { settings.put("boot-java", bootJavaObj); harness.changeConfiguration(new Settings(new Gson().toJsonTree(settings))); + // Configuration change updates indexer hence we need to wait until this occurs as well + indexer.waitOperation(); directory = new File(ProjectsHarness.class.getResource("/test-projects/test-xml-hyperlinks/").toURI()); diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/xml/test/XMLBeansHyperlinkTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/xml/test/XMLBeansHyperlinkTest.java index 7badf906d..10245d3d8 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/xml/test/XMLBeansHyperlinkTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/xml/test/XMLBeansHyperlinkTest.java @@ -100,6 +100,8 @@ public class XMLBeansHyperlinkTest { settings.put("boot-java", bootJavaObj); harness.changeConfiguration(new Settings(new Gson().toJsonTree(settings))); + // Configuration change updates indexer hence we need to wait until this occurs as well + indexer.waitOperation(); project = projects.mavenProject("test-xml-hyperlinks"); @@ -178,8 +180,9 @@ public class XMLBeansHyperlinkTest { @Test // @Disabled void testBeanRefHyperlink() throws Exception { + assertEquals(springIndex.getBeans().length, 4); + Bean[] beans = springIndex.getBeansWithName(project.getElementName(), "simpleObj"); - assertEquals(1, beans.length); assertEquals("simpleObj", beans[0].getName()); assertEquals("u.t.r.SimpleObj", beans[0].getType()); diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/xml/test/XMLContentAssistTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/xml/test/XMLContentAssistTest.java index 39293c86e..ed53c4c90 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/xml/test/XMLContentAssistTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/xml/test/XMLContentAssistTest.java @@ -78,6 +78,8 @@ public class XMLContentAssistTest { settings.put("boot-java", bootJavaObj); harness.changeConfiguration(new Settings(new Gson().toJsonTree(settings))); + // Configuration change updates indexer hence we need to wait until this occurs as well + indexer.waitOperation(); project = projects.mavenProject("test-xml-hyperlinks");